merge from dev-exp
This commit is contained in:
commit
9a532037df
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(libmimalloc C CXX)
|
||||
include("cmake/mimalloc-config-version.cmake")
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@ -14,10 +14,14 @@ option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanis
|
||||
option(MI_BUILD_TESTS "Build test executables" ON)
|
||||
option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF)
|
||||
|
||||
include("cmake/mimalloc-config-version.cmake")
|
||||
|
||||
set(mi_sources
|
||||
src/stats.c
|
||||
src/random.c
|
||||
src/os.c
|
||||
src/memory.c
|
||||
src/arena.c
|
||||
src/region.c
|
||||
src/segment.c
|
||||
src/page.c
|
||||
src/alloc.c
|
||||
@ -50,7 +54,7 @@ endif()
|
||||
# Process options
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel")
|
||||
set(MI_USE_CXX "ON")
|
||||
endif()
|
||||
|
||||
@ -92,27 +96,38 @@ endif()
|
||||
if(MI_USE_CXX MATCHES "ON")
|
||||
message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)")
|
||||
set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX )
|
||||
set_source_files_properties(src/static.c test/test-api.c PROPERTIES LANGUAGE CXX )
|
||||
set_source_files_properties(src/static.c test/test-api.c test/test-stress PROPERTIES LANGUAGE CXX )
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang|Clang")
|
||||
list(APPEND mi_cflags -Wno-deprecated)
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
||||
list(APPEND mi_cflags -Kc++)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Compiler flags
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU")
|
||||
list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas)
|
||||
list(APPEND mi_cflags -Wall -Wextra -Wno-unknown-pragmas -fvisibility=hidden)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
|
||||
list(APPEND mi_cflags -Wno-invalid-memory-model)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||
list(APPEND mi_cflags -Wall -fvisibility=hidden)
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel")
|
||||
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)
|
||||
list(APPEND mi_cflags -fbranch-target-load-optimize)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# extra needed libraries
|
||||
if(WIN32)
|
||||
list(APPEND mi_libraries psapi shell32 user32)
|
||||
list(APPEND mi_libraries psapi shell32 user32 bcrypt)
|
||||
else()
|
||||
list(APPEND mi_libraries pthread)
|
||||
find_library(LIBRT rt)
|
||||
|
@ -13,16 +13,31 @@ jobs:
|
||||
pool:
|
||||
vmImage:
|
||||
windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
Debug:
|
||||
BuildType: debug
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||
Release:
|
||||
BuildType: release
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
||||
Secure:
|
||||
BuildType: secure
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||
steps:
|
||||
- task: CMake@1
|
||||
inputs:
|
||||
workingDirectory: 'build'
|
||||
cmakeArgs: ..
|
||||
workingDirectory: $(BuildType)
|
||||
cmakeArgs: .. $(cmakeExtraArgs)
|
||||
- task: MSBuild@1
|
||||
inputs:
|
||||
solution: build/libmimalloc.sln
|
||||
- upload: $(Build.SourcesDirectory)/build
|
||||
artifact: windows
|
||||
solution: $(BuildType)/libmimalloc.sln
|
||||
- script: |
|
||||
cd $(BuildType)
|
||||
ctest
|
||||
displayName: CTest
|
||||
- upload: $(Build.SourcesDirectory)/$(BuildType)
|
||||
artifact: mimalloc-windows-$(BuildType)
|
||||
|
||||
- job:
|
||||
displayName: Linux
|
||||
@ -46,6 +61,11 @@ jobs:
|
||||
CXX: g++
|
||||
BuildType: secure
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||
Debug++:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BuildType: debug-cxx
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON
|
||||
Debug Clang:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
@ -61,32 +81,47 @@ jobs:
|
||||
CXX: clang++
|
||||
BuildType: secure-clang
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||
|
||||
Debug++ Clang:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
BuildType: debug-clang-cxx
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON
|
||||
steps:
|
||||
- task: CMake@1
|
||||
inputs:
|
||||
workingDirectory: $(BuildType)
|
||||
cmakeArgs: .. $(cmakeExtraArgs)
|
||||
|
||||
- script: make -j$(nproc) -C $(BuildType)
|
||||
displayName: Make
|
||||
|
||||
- script: make test -C $(BuildType)
|
||||
displayName: Ctest
|
||||
|
||||
displayName: CTest
|
||||
- upload: $(Build.SourcesDirectory)/$(BuildType)
|
||||
artifact: ubuntu-$(BuildType)
|
||||
artifact: mimalloc-ubuntu-$(BuildType)
|
||||
|
||||
- job:
|
||||
displayName: macOS
|
||||
pool:
|
||||
vmImage:
|
||||
macOS-10.14
|
||||
strategy:
|
||||
matrix:
|
||||
Debug:
|
||||
BuildType: debug
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||
Release:
|
||||
BuildType: release
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
||||
Secure:
|
||||
BuildType: secure
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||
steps:
|
||||
- task: CMake@1
|
||||
inputs:
|
||||
workingDirectory: 'build'
|
||||
cmakeArgs: ..
|
||||
- script: make -j$(sysctl -n hw.ncpu) -C build
|
||||
- upload: $(Build.SourcesDirectory)/build
|
||||
artifact: macos
|
||||
workingDirectory: $(BuildType)
|
||||
cmakeArgs: .. $(cmakeExtraArgs)
|
||||
- script: make -j$(sysctl -n hw.ncpu) -C $(BuildType)
|
||||
displayName: Make
|
||||
- script: make test -C $(BuildType)
|
||||
displayName: CTest
|
||||
- upload: $(Build.SourcesDirectory)/$(BuildType)
|
||||
artifact: mimalloc-macos-$(BuildType)
|
||||
|
@ -1,5 +1,5 @@
|
||||
set(mi_version_major 1)
|
||||
set(mi_version_minor 2)
|
||||
set(mi_version_minor 5)
|
||||
set(mi_version ${mi_version_major}.${mi_version_minor})
|
||||
|
||||
set(PACKAGE_VERSION ${mi_version})
|
||||
|
886
doc/bench-c5-18xlarge-2020-01-20-a.svg
Normal file
886
doc/bench-c5-18xlarge-2020-01-20-a.svg
Normal file
@ -0,0 +1,886 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- This file was generated by dvisvgm 2.4.2 -->
|
||||
<svg height='167.731pt' version='1.1' viewBox='52.938 54.996 381.624 167.731' width='381.624pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
|
||||
<defs>
|
||||
<clipPath id='clip1'>
|
||||
<path d='M82.148 206.586H434.164V81.34H82.148Z'/>
|
||||
</clipPath>
|
||||
<use id='g3-40' transform='scale(1.143)' xlink:href='#g0-40'/>
|
||||
<use id='g3-41' transform='scale(1.143)' xlink:href='#g0-41'/>
|
||||
<use id='g3-78' transform='scale(1.143)' xlink:href='#g0-78'/>
|
||||
<use id='g3-97' transform='scale(1.143)' xlink:href='#g0-97'/>
|
||||
<use id='g3-98' transform='scale(1.143)' xlink:href='#g0-98'/>
|
||||
<use id='g3-99' transform='scale(1.143)' xlink:href='#g0-99'/>
|
||||
<use id='g3-100' transform='scale(1.143)' xlink:href='#g0-100'/>
|
||||
<use id='g3-101' transform='scale(1.143)' xlink:href='#g0-101'/>
|
||||
<use id='g3-102' transform='scale(1.143)' xlink:href='#g0-102'/>
|
||||
<use id='g3-105' transform='scale(1.143)' xlink:href='#g0-105'/>
|
||||
<use id='g3-108' transform='scale(1.143)' xlink:href='#g0-108'/>
|
||||
<use id='g3-109' transform='scale(1.143)' xlink:href='#g0-109'/>
|
||||
<use id='g3-110' transform='scale(1.143)' xlink:href='#g0-110'/>
|
||||
<use id='g3-111' transform='scale(1.143)' xlink:href='#g0-111'/>
|
||||
<use id='g3-112' transform='scale(1.143)' xlink:href='#g0-112'/>
|
||||
<use id='g3-114' transform='scale(1.143)' xlink:href='#g0-114'/>
|
||||
<use id='g3-115' transform='scale(1.143)' xlink:href='#g0-115'/>
|
||||
<use id='g3-116' transform='scale(1.143)' xlink:href='#g0-116'/>
|
||||
<use id='g3-119' transform='scale(1.143)' xlink:href='#g0-119'/>
|
||||
<path d='M3.891 -2.914C4.806 -3.165 5.452 -3.811 5.452 -4.546C5.452 -5.469 4.411 -6.223 3.129 -6.223H0.87V0H1.704V-2.824H3.138L4.842 0H5.703L3.891 -2.914ZM1.704 -3.407V-5.694H3.022C4.062 -5.694 4.671 -5.192 4.671 -4.546C4.671 -3.963 4.125 -3.407 3.022 -3.407H1.704Z' id='g1-82'/>
|
||||
<path d='M3.694 -2.591C3.694 -3.479 3.04 -4.133 2.152 -4.133C1.569 -4.133 1.139 -3.981 0.708 -3.739L0.762 -3.102C1.21 -3.434 1.65 -3.569 2.143 -3.569C2.645 -3.569 2.95 -3.165 2.95 -2.582V-2.206C1.408 -2.17 0.395 -1.766 0.395 -1.04C0.395 -0.619 0.672 0.099 1.453 0.099C1.632 0.099 2.412 0.081 2.977 -0.341V0H3.694V-2.591ZM2.95 -1.255C2.95 -1.067 2.95 -0.843 2.627 -0.655C2.403 -0.52 2.107 -0.484 1.928 -0.484C1.47 -0.484 1.085 -0.699 1.085 -1.058C1.085 -1.695 2.833 -1.722 2.95 -1.722V-1.255Z' id='g1-97'/>
|
||||
<path d='M3.829 -1.964C3.829 -2.242 3.82 -2.923 3.47 -3.461C3.093 -4.026 2.52 -4.133 2.179 -4.133C1.139 -4.133 0.314 -3.174 0.314 -2.026C0.314 -0.843 1.193 0.099 2.313 0.099C2.744 0.099 3.264 -0.009 3.784 -0.341L3.73 -0.959C3.165 -0.556 2.636 -0.484 2.322 -0.484C1.578 -0.484 1.004 -1.139 0.977 -1.964H3.829ZM1.031 -2.493C1.175 -3.067 1.614 -3.551 2.179 -3.551C2.511 -3.551 3.12 -3.398 3.291 -2.493H1.031Z' id='g1-101'/>
|
||||
<path d='M1.524 -6.133H0.664V-5.272H1.524V-6.133ZM1.453 -3.981H0.735V0H1.453V-3.981Z' id='g1-105'/>
|
||||
<path d='M1.453 -6.223H0.735V0H1.453V-6.223Z' id='g1-108'/>
|
||||
<path d='M6.581 -2.663C6.581 -3.327 6.402 -4.08 5.317 -4.08C4.564 -4.08 4.142 -3.622 3.927 -3.344C3.865 -3.524 3.676 -4.08 2.762 -4.08C2.053 -4.08 1.623 -3.667 1.417 -3.398V-4.035H0.726V0H1.47V-2.188C1.47 -2.78 1.704 -3.497 2.385 -3.497C3.282 -3.497 3.282 -2.86 3.282 -2.6V0H4.026V-2.188C4.026 -2.78 4.259 -3.497 4.94 -3.497C5.837 -3.497 5.837 -2.86 5.837 -2.6V0H6.581V-2.663Z' id='g1-109'/>
|
||||
<path d='M1.623 -3.425H2.914V-3.981H1.623V-5.12H0.959V-3.981H0.17V-3.425H0.933V-1.13C0.933 -0.601 1.049 0.099 1.704 0.099C2.098 0.099 2.564 0.018 3.067 -0.233L2.914 -0.798C2.681 -0.619 2.367 -0.511 2.089 -0.511C1.739 -0.511 1.623 -0.825 1.623 -1.291V-3.425Z' id='g1-116'/>
|
||||
<path d='M4.116 -3.981H3.407L2.699 -2.161C2.52 -1.695 2.188 -0.825 2.143 -0.493H2.125C2.107 -0.646 2.08 -0.816 1.587 -2.107C1.318 -2.833 0.879 -3.927 0.861 -3.981H0.126L1.704 0H2.537L4.116 -3.981Z' id='g1-118'/>
|
||||
<use id='g2-46' transform='scale(0.714)' xlink:href='#g0-46'/>
|
||||
<use id='g2-48' transform='scale(0.714)' xlink:href='#g0-48'/>
|
||||
<use id='g2-49' transform='scale(0.714)' xlink:href='#g0-49'/>
|
||||
<use id='g2-50' transform='scale(0.714)' xlink:href='#g0-50'/>
|
||||
<use id='g2-51' transform='scale(0.714)' xlink:href='#g0-51'/>
|
||||
<use id='g2-52' transform='scale(0.714)' xlink:href='#g0-52'/>
|
||||
<use id='g2-53' transform='scale(0.714)' xlink:href='#g0-53'/>
|
||||
<use id='g2-54' transform='scale(0.714)' xlink:href='#g0-54'/>
|
||||
<use id='g2-55' transform='scale(0.714)' xlink:href='#g0-55'/>
|
||||
<use id='g2-56' transform='scale(0.714)' xlink:href='#g0-56'/>
|
||||
<use id='g2-57' transform='scale(0.714)' xlink:href='#g0-57'/>
|
||||
<use id='g2-120' transform='scale(0.714)' xlink:href='#g0-120'/>
|
||||
<path d='M1.445 -1.245C1.445 -1.41 1.305 -1.549 1.141 -1.549S0.837 -1.41 0.837 -1.245S0.976 -0.941 1.141 -0.941S1.445 -1.081 1.445 -1.245Z' id='g4-1'/>
|
||||
<path d='M2.127 -5.23C2.008 -5.23 1.995 -5.23 1.911 -5.154C1.032 -4.387 0.586 -3.145 0.586 -1.743C0.586 -0.425 0.983 0.844 1.904 1.653C1.995 1.743 2.008 1.743 2.127 1.743H2.462C2.441 1.73 1.764 1.151 1.444 0.063C1.276 -0.481 1.193 -1.053 1.193 -1.743C1.193 -4.156 2.322 -5.112 2.462 -5.23H2.127Z' id='g0-40'/>
|
||||
<path d='M0.746 1.743C0.865 1.743 0.879 1.743 0.962 1.667C1.841 0.9 2.287 -0.342 2.287 -1.743C2.287 -3.062 1.89 -4.331 0.969 -5.14C0.879 -5.23 0.865 -5.23 0.746 -5.23H0.411C0.432 -5.216 1.109 -4.638 1.43 -3.55C1.597 -3.006 1.681 -2.434 1.681 -1.743C1.681 0.669 0.551 1.625 0.411 1.743H0.746Z' id='g0-41'/>
|
||||
<path d='M1.339 -0.628H0.711V0H1.339V-0.628Z' id='g0-46'/>
|
||||
<path d='M3.403 -2.267C3.403 -2.601 3.403 -3.417 3.075 -3.989C2.72 -4.617 2.183 -4.721 1.848 -4.721C1.534 -4.721 0.99 -4.624 0.642 -4.024C0.307 -3.466 0.293 -2.706 0.293 -2.267C0.293 -1.75 0.321 -1.116 0.614 -0.586C0.921 -0.021 1.437 0.146 1.848 0.146C2.545 0.146 2.929 -0.258 3.138 -0.697C3.382 -1.193 3.403 -1.834 3.403 -2.267ZM1.848 -0.314C1.555 -0.314 1.22 -0.481 1.046 -0.983C0.907 -1.409 0.9 -1.848 0.9 -2.357C0.9 -2.999 0.9 -4.261 1.848 -4.261S2.797 -2.999 2.797 -2.357C2.797 -1.897 2.797 -1.374 2.629 -0.928C2.434 -0.425 2.078 -0.314 1.848 -0.314Z' id='g0-48'/>
|
||||
<path d='M2.239 -4.721H2.085C1.632 -4.303 1.06 -4.275 0.642 -4.261V-3.822C0.914 -3.829 1.262 -3.843 1.611 -3.982V-0.439H0.683V0H3.166V-0.439H2.239V-4.721Z' id='g0-49'/>
|
||||
<path d='M1.974 -0.537C1.89 -0.537 1.806 -0.53 1.723 -0.53H0.928L2.008 -1.485C2.134 -1.597 2.476 -1.855 2.608 -1.967C2.915 -2.246 3.327 -2.608 3.327 -3.215C3.327 -4.003 2.741 -4.721 1.743 -4.721C1.004 -4.721 0.544 -4.324 0.307 -3.612L0.635 -3.201C0.795 -3.787 1.039 -4.24 1.646 -4.24C2.232 -4.24 2.678 -3.829 2.678 -3.201C2.678 -2.622 2.336 -2.294 1.918 -1.897C1.778 -1.757 1.402 -1.444 1.255 -1.304C1.053 -1.123 0.572 -0.656 0.37 -0.481V0H3.327V-0.537H1.974Z' id='g0-50'/>
|
||||
<path d='M0.697 -3.578C0.983 -4.135 1.485 -4.289 1.82 -4.289C2.232 -4.289 2.538 -4.052 2.538 -3.654C2.538 -3.285 2.287 -2.831 1.757 -2.741C1.723 -2.734 1.695 -2.734 1.234 -2.699V-2.239H1.778C2.441 -2.239 2.685 -1.716 2.685 -1.276C2.685 -0.732 2.35 -0.314 1.806 -0.314C1.311 -0.314 0.746 -0.551 0.398 -0.997L0.307 -0.544C0.711 -0.091 1.276 0.146 1.82 0.146C2.734 0.146 3.389 -0.537 3.389 -1.269C3.389 -1.841 2.929 -2.301 2.378 -2.462C2.908 -2.734 3.18 -3.201 3.18 -3.654C3.18 -4.247 2.573 -4.721 1.827 -4.721C1.213 -4.721 0.704 -4.4 0.411 -3.982L0.697 -3.578Z' id='g0-51'/>
|
||||
<path d='M2.762 -1.165H3.487V-1.625H2.762V-4.575H2.071L0.209 -1.625V-1.165H2.162V0H2.762V-1.165ZM0.802 -1.625C1.011 -1.953 2.211 -3.815 2.211 -4.233V-1.625H0.802Z' id='g0-52'/>
|
||||
<path d='M1.144 -4.094H3.075V-4.575H0.586V-1.967H1.095C1.262 -2.343 1.59 -2.511 1.904 -2.511C2.19 -2.511 2.622 -2.315 2.622 -1.43C2.622 -0.516 2.043 -0.314 1.688 -0.314C1.227 -0.314 0.781 -0.558 0.544 -0.955L0.279 -0.537C0.621 -0.112 1.137 0.146 1.688 0.146C2.608 0.146 3.327 -0.565 3.327 -1.416C3.327 -2.28 2.685 -2.971 1.918 -2.971C1.618 -2.971 1.353 -2.866 1.144 -2.692V-4.094Z' id='g0-53'/>
|
||||
<path d='M3.062 -4.582C2.685 -4.721 2.42 -4.721 2.287 -4.721C1.227 -4.721 0.307 -3.724 0.307 -2.253C0.307 -0.363 1.158 0.146 1.862 0.146C2.427 0.146 2.72 -0.119 2.936 -0.342C3.382 -0.816 3.389 -1.311 3.389 -1.555C3.389 -2.469 2.894 -3.229 2.218 -3.229C1.534 -3.229 1.165 -2.873 0.962 -2.671C1.053 -3.626 1.541 -4.289 2.294 -4.289C2.434 -4.289 2.713 -4.275 3.062 -4.142V-4.582ZM0.969 -1.534C0.969 -1.576 0.969 -1.681 0.976 -1.716C0.976 -2.19 1.276 -2.769 1.897 -2.769C2.748 -2.769 2.748 -1.792 2.748 -1.555C2.748 -1.29 2.748 -0.997 2.559 -0.704C2.392 -0.453 2.183 -0.314 1.862 -0.314C1.123 -0.314 1.004 -1.227 0.969 -1.534Z' id='g0-54'/>
|
||||
<path d='M1.723 -4.038C1.806 -4.038 1.89 -4.045 1.974 -4.045H2.852C1.792 -3.006 1.116 -1.548 1.116 0.07H1.771C1.771 -1.967 2.762 -3.431 3.389 -4.087V-4.575H0.307V-4.038H1.723Z' id='g0-55'/>
|
||||
<path d='M2.385 -2.469C2.845 -2.615 3.285 -2.985 3.285 -3.501C3.285 -4.135 2.678 -4.721 1.848 -4.721S0.411 -4.135 0.411 -3.501C0.411 -2.978 0.865 -2.608 1.311 -2.469C0.697 -2.28 0.307 -1.806 0.307 -1.269C0.307 -0.523 0.969 0.146 1.848 0.146S3.389 -0.523 3.389 -1.269C3.389 -1.806 2.992 -2.28 2.385 -2.469ZM1.848 -2.699C1.353 -2.699 0.948 -2.985 0.948 -3.494C0.948 -3.94 1.262 -4.289 1.848 -4.289C2.427 -4.289 2.748 -3.94 2.748 -3.494C2.748 -2.999 2.357 -2.699 1.848 -2.699ZM1.848 -0.314C1.367 -0.314 0.941 -0.621 0.941 -1.276C0.941 -1.904 1.346 -2.239 1.848 -2.239S2.755 -1.897 2.755 -1.276C2.755 -0.621 2.322 -0.314 1.848 -0.314Z' id='g0-56'/>
|
||||
<path d='M0.537 -0.174C0.879 0.077 1.193 0.146 1.52 0.146C2.497 0.146 3.389 -0.837 3.389 -2.336C3.389 -4.24 2.545 -4.721 1.876 -4.721C1.255 -4.721 0.969 -4.428 0.767 -4.226C0.321 -3.773 0.307 -3.292 0.307 -3.02C0.307 -2.12 0.795 -1.346 1.478 -1.346C2.267 -1.346 2.699 -1.869 2.734 -1.911C2.636 -0.802 2.092 -0.314 1.52 -0.314C1.158 -0.314 0.934 -0.446 0.774 -0.579L0.537 -0.174ZM2.713 -3.027C2.72 -2.985 2.72 -2.915 2.72 -2.873C2.72 -2.357 2.406 -1.806 1.799 -1.806C1.534 -1.806 1.325 -1.883 1.144 -2.169C0.962 -2.441 0.948 -2.706 0.948 -3.02C0.948 -3.292 0.948 -3.605 1.165 -3.912C1.311 -4.122 1.52 -4.289 1.869 -4.289C2.545 -4.289 2.692 -3.473 2.713 -3.027Z' id='g0-57'/>
|
||||
<path d='M1.646 -4.84H0.697V0H1.283V-4.289H1.29L3.578 0H4.526V-4.84H3.94V-0.551H3.933L1.646 -4.84Z' id='g0-78'/>
|
||||
<path d='M2.971 -2.008C2.971 -2.72 2.427 -3.201 1.736 -3.201C1.297 -3.201 0.962 -3.11 0.572 -2.901L0.614 -2.392C0.844 -2.545 1.186 -2.755 1.736 -2.755C2.043 -2.755 2.364 -2.525 2.364 -2.001V-1.723C1.332 -1.688 0.314 -1.471 0.314 -0.823C0.314 -0.474 0.551 0.07 1.165 0.07C1.465 0.07 2.015 0.007 2.385 -0.265V0H2.971V-2.008ZM2.364 -0.99C2.364 -0.851 2.364 -0.669 2.12 -0.523C1.897 -0.398 1.625 -0.391 1.548 -0.391C1.165 -0.391 0.872 -0.565 0.872 -0.83C0.872 -1.276 2.05 -1.318 2.364 -1.332V-0.99Z' id='g0-97'/>
|
||||
<path d='M1.179 -4.84H0.593V0H1.2V-0.328C1.353 -0.195 1.688 0.07 2.197 0.07C2.957 0.07 3.571 -0.642 3.571 -1.555C3.571 -2.399 3.089 -3.166 2.392 -3.166C1.953 -3.166 1.527 -3.027 1.179 -2.769V-4.84ZM1.2 -2.197C1.2 -2.308 1.2 -2.392 1.444 -2.552C1.548 -2.615 1.736 -2.706 1.974 -2.706C2.441 -2.706 2.964 -2.392 2.964 -1.555C2.964 -0.704 2.385 -0.391 1.897 -0.391C1.639 -0.391 1.395 -0.509 1.2 -0.823V-2.197Z' id='g0-98'/>
|
||||
<path d='M3.034 -0.76C2.685 -0.537 2.308 -0.411 1.876 -0.411C1.234 -0.411 0.858 -0.928 0.858 -1.555C0.858 -2.092 1.137 -2.72 1.897 -2.72C2.371 -2.72 2.594 -2.622 2.95 -2.399L3.041 -2.901C2.622 -3.11 2.441 -3.201 1.897 -3.201C0.851 -3.201 0.251 -2.357 0.251 -1.548C0.251 -0.697 0.921 0.07 1.869 0.07C2.357 0.07 2.776 -0.077 3.075 -0.251L3.034 -0.76Z' id='g0-99'/>
|
||||
<path d='M3.229 -4.84H2.643V-2.797C2.197 -3.124 1.743 -3.166 1.541 -3.166C0.809 -3.166 0.251 -2.434 0.251 -1.548S0.802 0.07 1.52 0.07C1.953 0.07 2.357 -0.126 2.622 -0.363V0H3.229V-4.84ZM2.622 -0.865C2.448 -0.579 2.183 -0.391 1.848 -0.391C1.36 -0.391 0.858 -0.732 0.858 -1.541C0.858 -2.413 1.451 -2.706 1.925 -2.706C2.204 -2.706 2.441 -2.587 2.622 -2.35V-0.865Z' id='g0-100'/>
|
||||
<path d='M2.999 -0.76C2.608 -0.481 2.169 -0.391 1.869 -0.391C1.262 -0.391 0.802 -0.886 0.781 -1.527H3.068C3.068 -1.848 3.034 -2.315 2.762 -2.713C2.511 -3.068 2.092 -3.201 1.75 -3.201C0.9 -3.201 0.244 -2.455 0.244 -1.569C0.244 -0.676 0.941 0.07 1.862 0.07C2.267 0.07 2.685 -0.049 3.041 -0.265L2.999 -0.76ZM0.83 -1.946C0.99 -2.504 1.402 -2.741 1.75 -2.741C2.057 -2.741 2.511 -2.594 2.643 -1.946H0.83Z' id='g0-101'/>
|
||||
<path d='M1.325 -2.657H2.12V-3.096H1.304V-3.898C1.304 -4.38 1.743 -4.449 1.974 -4.449C2.12 -4.449 2.308 -4.428 2.566 -4.331V-4.84C2.385 -4.882 2.169 -4.91 1.981 -4.91C1.262 -4.91 0.739 -4.394 0.739 -3.703V-3.096H0.202V-2.657H0.739V0H1.325V-2.657Z' id='g0-102'/>
|
||||
<path d='M1.227 -4.784H0.523V-4.08H1.227V-4.784ZM1.172 -3.096H0.586V0H1.172V-3.096Z' id='g0-105'/>
|
||||
<path d='M1.172 -4.84H0.586V0H1.172V-4.84Z' id='g0-108'/>
|
||||
<path d='M5.3 -2.064C5.3 -2.608 5.14 -3.166 4.282 -3.166C3.696 -3.166 3.333 -2.824 3.166 -2.601C3.096 -2.79 2.922 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-1.695C3.243 -2.155 3.438 -2.706 3.975 -2.706C4.693 -2.706 4.693 -2.218 4.693 -2.015V0H5.3V-2.064Z' id='g0-109'/>
|
||||
<path d='M3.243 -2.064C3.243 -2.608 3.082 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-2.064Z' id='g0-110'/>
|
||||
<path d='M3.487 -1.527C3.487 -2.448 2.755 -3.201 1.848 -3.201S0.209 -2.441 0.209 -1.527C0.209 -0.642 0.948 0.07 1.848 0.07C2.755 0.07 3.487 -0.642 3.487 -1.527ZM1.848 -0.411C1.297 -0.411 0.816 -0.816 0.816 -1.604S1.332 -2.741 1.848 -2.741C2.371 -2.741 2.88 -2.378 2.88 -1.604C2.88 -0.809 2.385 -0.411 1.848 -0.411Z' id='g0-111'/>
|
||||
<path d='M1.2 -0.328C1.569 0.007 1.967 0.07 2.204 0.07C2.943 0.07 3.571 -0.635 3.571 -1.555C3.571 -2.392 3.11 -3.166 2.42 -3.166C2.106 -3.166 1.583 -3.075 1.179 -2.762V-3.096H0.593V1.353H1.2V-0.328ZM1.2 -2.315C1.36 -2.511 1.632 -2.685 1.967 -2.685C2.525 -2.685 2.964 -2.169 2.964 -1.555C2.964 -0.865 2.441 -0.391 1.897 -0.391C1.792 -0.391 1.618 -0.404 1.437 -0.551C1.227 -0.711 1.2 -0.816 1.2 -0.948V-2.315Z' id='g0-112'/>
|
||||
<path d='M1.179 -1.485C1.179 -2.239 1.806 -2.643 2.42 -2.65V-3.166C1.834 -3.159 1.409 -2.873 1.13 -2.504V-3.145H0.593V0H1.179V-1.485Z' id='g0-114'/>
|
||||
<path d='M2.545 -2.985C2.071 -3.18 1.723 -3.201 1.471 -3.201C1.297 -3.201 0.244 -3.201 0.244 -2.273C0.244 -1.946 0.425 -1.764 0.516 -1.681C0.76 -1.437 1.053 -1.381 1.423 -1.311C1.75 -1.248 2.127 -1.179 2.127 -0.844C2.127 -0.404 1.548 -0.404 1.451 -0.404C1.004 -0.404 0.586 -0.565 0.307 -0.76L0.209 -0.237C0.446 -0.119 0.872 0.07 1.451 0.07C1.764 0.07 2.071 0.021 2.329 -0.167C2.587 -0.363 2.671 -0.669 2.671 -0.907C2.671 -1.032 2.657 -1.304 2.364 -1.569C2.106 -1.799 1.855 -1.848 1.52 -1.911C1.109 -1.988 0.788 -2.05 0.788 -2.357C0.788 -2.755 1.297 -2.755 1.402 -2.755C1.799 -2.755 2.106 -2.671 2.455 -2.49L2.545 -2.985Z' id='g0-115'/>
|
||||
<path d='M1.311 -2.657H2.343V-3.096H1.311V-3.982H0.774V-3.096H0.139V-2.657H0.753V-0.893C0.753 -0.425 0.872 0.07 1.374 0.07S2.26 -0.091 2.469 -0.188L2.35 -0.635C2.12 -0.467 1.876 -0.411 1.681 -0.411C1.388 -0.411 1.311 -0.697 1.311 -1.018V-2.657Z' id='g0-116'/>
|
||||
<path d='M4.951 -3.096H4.407C4.345 -2.901 3.954 -1.723 3.738 -0.997C3.682 -0.795 3.612 -0.572 3.592 -0.411H3.585C3.543 -0.697 3.299 -1.451 3.285 -1.499L2.769 -3.096H2.239C2.036 -2.497 1.513 -0.934 1.458 -0.425H1.451C1.395 -0.921 0.879 -2.462 0.767 -2.797C0.711 -2.964 0.711 -2.978 0.676 -3.096H0.105L1.123 0H1.709C1.716 -0.028 1.904 -0.579 2.148 -1.353C2.253 -1.695 2.462 -2.364 2.497 -2.671L2.504 -2.678C2.518 -2.532 2.559 -2.378 2.608 -2.204S2.706 -1.841 2.755 -1.681L3.292 0H3.933L4.951 -3.096Z' id='g0-119'/>
|
||||
<path d='M1.932 -1.597L3.285 -3.096H2.671L1.681 -1.953L0.669 -3.096H0.042L1.437 -1.597L0 0H0.621L1.681 -1.311L2.783 0H3.41L1.932 -1.597Z' id='g0-120'/>
|
||||
</defs>
|
||||
<g id='page1'>
|
||||
<path d='M140.82 215.441V206.586M199.488 215.441V206.586M258.156 215.441V206.586M316.824 215.441V206.586M375.496 215.441V206.586M140.82 72.48V81.34M199.488 72.48V81.34M258.156 72.48V81.34M316.824 72.48V81.34M375.496 72.48V81.34' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M111.484 210.836V206.586M170.152 210.836V206.586M228.824 210.836V206.586M287.492 210.836V206.586M346.16 210.836V206.586M404.828 210.836V206.586M111.484 77.086V81.34M170.152 77.086V81.34M228.824 77.086V81.34M287.492 77.086V81.34M346.16 77.086V81.34M404.828 77.086V81.34' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 206.586H86.402M82.148 175.273H86.402M82.148 143.961H86.402M82.148 112.648H86.402M82.148 81.34H86.402M434.164 206.586H429.91M434.164 175.273H429.91M434.164 143.961H429.91M434.164 112.648H429.91M434.164 81.34H429.91' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 206.586V81.34H434.164V206.586H82.148Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(1 0 0 1 -11.54 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-99' y='186.027'/>
|
||||
<use x='118.25' xlink:href='#g3-102' y='186.027'/>
|
||||
<use x='120.838' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='123.73' xlink:href='#g3-97' y='186.027'/>
|
||||
<use x='127.798' xlink:href='#g3-99' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 45.565 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='186.027'/>
|
||||
<use x='116.507' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='120.271' xlink:href='#g3-97' y='186.027'/>
|
||||
<use x='124.339' xlink:href='#g3-110' y='186.027'/>
|
||||
<use x='128.711' xlink:href='#g3-78' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 106.188 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='117.379' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='121.142' xlink:href='#g3-100' y='186.027'/>
|
||||
<use x='125.515' xlink:href='#g3-105' y='186.027'/>
|
||||
<use x='127.535' xlink:href='#g3-115' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 159.716 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='186.027'/>
|
||||
<use x='116.507' xlink:href='#g3-97' y='186.027'/>
|
||||
<use x='120.34' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='123.232' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='126.478' xlink:href='#g3-111' y='186.027'/>
|
||||
<use x='130.712' xlink:href='#g3-110' y='186.027'/>
|
||||
<use x='135.085' xlink:href='#g3-78' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 215.596 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-109' y='186.027'/>
|
||||
<use x='121.211' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='124.458' xlink:href='#g3-116' y='186.027'/>
|
||||
<use x='127.516' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='130.408' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='134.171' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='137.418' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='140.664' xlink:href='#g3-78' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 277.158 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='117.379' xlink:href='#g3-112' y='186.027'/>
|
||||
<use x='121.751' xlink:href='#g3-116' y='186.027'/>
|
||||
<use x='124.809' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='128.573' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='131.819' xlink:href='#g3-116' y='186.027'/>
|
||||
<use x='134.877' xlink:href='#g3-78' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -40.942 22.192)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -9.12)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -40.431)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -71.743)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -103.054)'>
|
||||
<use x='114.487' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<path clip-path='url(#clip1)' d='M82.148 143.961H434.164' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M88.945 206.586H92.18V143.961H88.945ZM147.613 206.586H150.852V143.961H147.613ZM206.281 206.586H209.52V143.961H206.281ZM264.949 206.586H268.188V143.961H264.949ZM323.621 206.586H326.859V143.961H323.621ZM382.289 206.586H385.527V143.961H382.289Z' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M88.945 206.586H92.18V143.961H88.945ZM147.613 206.586H150.852V143.961H147.613ZM206.281 206.586H209.52V143.961H206.281ZM264.949 206.586H268.188V143.961H264.949ZM323.621 206.586H326.859V143.961H323.621ZM382.289 206.586H385.527V143.961H382.289Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M90.563 143.961V143.898' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M90.563 143.961V143.898' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M88.57 143.898H92.555' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M90.563 143.961V144.023' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M90.563 143.961V144.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M92.555 144.024H88.57' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M149.231 143.961V143.523' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M149.231 143.961V143.523' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M147.238 143.524H151.226' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M149.231 143.961V144.398' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M149.231 143.961V144.398' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M151.223 144.398H147.238' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M207.902 143.961V142.207' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M207.902 143.961V142.207' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M205.91 142.207H209.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M207.902 143.961V145.715' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M207.902 143.961V145.715' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M209.891 145.715H205.906' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M266.57 143.961V143.336' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M266.57 143.961V143.336' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M264.578 143.336H268.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M266.57 143.961V144.586' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M266.57 143.961V144.586' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M268.563 144.586H264.578' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M325.238 143.961V143.586' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M325.238 143.961V143.586' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M323.246 143.586H327.23' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M325.238 143.961V144.336' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M325.238 143.961V144.336' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M327.231 144.336H323.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M383.906 143.961V143.523' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M383.906 143.961V143.523' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M381.914 143.524H385.902' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M383.906 143.961V144.398' fill='#993333'/>
|
||||
<path clip-path='url(#clip1)' d='M383.906 143.961V144.398' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M385.898 144.398H381.914' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M94.176 206.586H97.41V142.519H94.176ZM152.844 206.586H156.082V140.203H152.844ZM211.512 206.586H214.75V148.344H211.512ZM270.18 206.586H273.418V121.418H270.18ZM328.852 206.586H332.09V135.07H328.852ZM387.52 206.586H390.758V81.34H387.52Z' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M94.176 206.586H97.41V142.519H94.176ZM152.844 206.586H156.082V140.203H152.844ZM211.512 206.586H214.75V148.344H211.512ZM270.18 206.586H273.418V121.418H270.18ZM328.852 206.586H332.09V135.07H328.852ZM387.52 206.586H390.758V81.34H387.52Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M95.793 142.519V142.519' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M93.801 142.52H97.785' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M95.793 142.519V142.519' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M93.801 142.52H97.785' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M154.461 140.203V139.203' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M154.461 140.203V139.203' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M152.469 139.203H156.457' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M154.461 140.203V141.207' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M154.461 140.203V141.207' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M156.453 141.207H152.468' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M213.133 148.344V148.031' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M213.133 148.344V148.031' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M211.141 148.032H215.125' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M213.133 148.344V148.656' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M213.133 148.344V148.656' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M215.121 148.656H211.136' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M271.801 121.418V121.23' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M271.801 121.418V121.23' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M269.809 121.23H273.793' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M271.801 121.418V121.605' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M271.801 121.418V121.605' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M273.793 121.606H269.808' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M330.469 135.07V134.254' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M330.469 135.07V134.254' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M328.477 134.254H332.461' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M330.469 135.07V135.883' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M330.469 135.07V135.883' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M332.461 135.883H328.476' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M389.137 81.34V81.34' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M387.145 81.34H391.133' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M389.137 81.34V81.34' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip1)' d='M387.145 81.34H391.133' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M99.406 206.586H102.641V140.266H99.406ZM158.074 206.586H161.313V142.898H158.074ZM216.742 206.586H219.981V134.754H216.742ZM275.41 206.586H278.649V99.25H275.41ZM334.082 206.586H337.32V81.34H334.082ZM392.75 206.586H395.988V81.34H392.75Z' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M99.406 206.586H102.641V140.266H99.406ZM158.074 206.586H161.313V142.898H158.074ZM216.742 206.586H219.981V134.754H216.742ZM275.41 206.586H278.649V99.25H275.41ZM334.082 206.586H337.32V81.34H334.082ZM392.75 206.586H395.988V81.34H392.75Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M101.024 140.266V140.203' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M101.024 140.266V140.203' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M99.031 140.203H103.016' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M101.024 140.266V140.328' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M101.024 140.266V140.328' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M103.016 140.328H99.031' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M159.691 142.898V142.269' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M159.691 142.898V142.269' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M157.699 142.269H161.687' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M159.691 142.898V143.523' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M159.691 142.898V143.523' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M161.684 143.524H157.699' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M218.363 134.754V134.066' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M218.363 134.754V134.066' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M216.371 134.067H220.355' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M218.363 134.754V135.445' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M218.363 134.754V135.445' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M220.352 135.445H216.367' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M277.031 99.25V91.168' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M277.031 99.25V91.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M275.039 91.172H279.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M277.031 99.25V107.328' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M277.031 99.25V107.328' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M279.024 107.328H275.039' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M335.699 81.34V81.34' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M333.707 81.34H337.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M335.699 81.34V81.34' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M333.707 81.34H337.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M394.367 81.34V81.34' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M392.375 81.34H396.363' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M394.367 81.34V81.34' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip1)' d='M392.375 81.34H396.363' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M104.637 206.586H107.871V124.859H104.637ZM163.305 206.586H166.543V141.207H163.305ZM221.973 206.586H225.211V118.035H221.973ZM280.641 206.586H283.879V121.043H280.641ZM339.313 206.586H342.551V133.066H339.313ZM397.981 206.586H401.219V89.039H397.981Z' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M104.637 206.586H107.871V124.859H104.637ZM163.305 206.586H166.543V141.207H163.305ZM221.973 206.586H225.211V118.035H221.973ZM280.641 206.586H283.879V121.043H280.641ZM339.313 206.586H342.551V133.066H339.313ZM397.981 206.586H401.219V89.039H397.981Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M106.254 124.859V124.797' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M106.254 124.859V124.797' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M104.261 124.796H108.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M106.254 124.859V124.922' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M106.254 124.859V124.922' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M108.246 124.922H104.261' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M164.922 141.207V140.894' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M164.922 141.207V140.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M162.929 140.895H166.917' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M164.922 141.207V141.519' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M164.922 141.207V141.519' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M166.914 141.52H162.929' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M223.594 118.035V117.973' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M223.594 118.035V117.973' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M221.601 117.973H225.585' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M223.594 118.035V118.098' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M223.594 118.035V118.098' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M225.582 118.098H221.597' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M282.262 121.043V120.539' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M282.262 121.043V120.539' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M280.269 120.539H284.253' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M282.262 121.043V121.543' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M282.262 121.043V121.543' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M284.254 121.543H280.269' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M340.93 133.066V132.812' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M340.93 133.066V132.812' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M338.937 132.812H342.921' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M340.93 133.066V133.316' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M340.93 133.066V133.316' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M342.922 133.316H338.937' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M399.598 89.039V88.539' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M399.598 89.039V88.539' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M397.605 88.539H401.593' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M399.598 89.039V89.543' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip1)' d='M399.598 89.039V89.543' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M401.59 89.543H397.605' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M109.867 206.586H113.102V142.332H109.867ZM168.535 206.586H171.774V143.086H168.535ZM227.203 206.586H230.442V132.125H227.203ZM285.871 206.586H289.109V139.641H285.871ZM344.543 206.586H347.781V81.34H344.543ZM403.211 206.586H406.449V100.187H403.211Z' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M109.867 206.586H113.102V142.332H109.867ZM168.535 206.586H171.774V143.086H168.535ZM227.203 206.586H230.442V132.125H227.203ZM285.871 206.586H289.109V139.641H285.871ZM344.543 206.586H347.781V81.34H344.543ZM403.211 206.586H406.449V100.187H403.211Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M111.484 142.332V142.269' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M111.484 142.332V142.269' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M109.492 142.269H113.477' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M111.484 142.332V142.394' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M111.484 142.332V142.394' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M113.477 142.395H109.492' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M170.152 143.086V142.644' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M170.152 143.086V142.644' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M168.16 142.644H172.145' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M170.152 143.086V143.523' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M170.152 143.086V143.523' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M172.145 143.524H168.16' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M228.824 132.125V131.312' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M228.824 132.125V131.312' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M226.832 131.312H230.816' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M228.824 132.125V132.941' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M228.824 132.125V132.941' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M230.813 132.941H226.828' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M287.492 139.641V138.387' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M287.492 139.641V138.387' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M285.5 138.387H289.484' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M287.492 139.641V140.894' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M287.492 139.641V140.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M289.485 140.895H285.5' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M346.16 81.34V81.34' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M344.168 81.34H348.152' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M346.16 81.34V81.34' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M344.168 81.34H348.152' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M404.828 100.187V99.562' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M404.828 100.187V99.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M402.836 99.562H406.824' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M404.828 100.187V100.812' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip1)' d='M404.828 100.187V100.812' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M406.821 100.813H402.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M115.098 206.586H118.332V135.57H115.098ZM173.766 206.586H177.004V136.07H173.766ZM232.434 206.586H235.672V114.965H232.434ZM291.102 206.586H294.34V113.84H291.102ZM349.774 206.586H353.012V81.34H349.774ZM408.442 206.586H411.68V81.34H408.442Z' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M115.098 206.586H118.332V135.57H115.098ZM173.766 206.586H177.004V136.07H173.766ZM232.434 206.586H235.672V114.965H232.434ZM291.102 206.586H294.34V113.84H291.102ZM349.774 206.586H353.012V81.34H349.774ZM408.442 206.586H411.68V81.34H408.442Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M116.715 135.57V135.508' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M116.715 135.57V135.508' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M114.722 135.508H118.707' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M116.715 135.57V135.633' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M116.715 135.57V135.633' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M118.707 135.633H114.722' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M175.383 136.07V135.258' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M175.383 136.07V135.258' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M173.39 135.258H177.375' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M175.383 136.07V136.883' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M175.383 136.07V136.883' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M177.375 136.883H173.39' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M234.055 114.965V114.09' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M234.055 114.965V114.09' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M232.062 114.09H236.046' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M234.055 114.965V115.844' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M234.055 114.965V115.844' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M236.043 115.843H232.058' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M292.723 113.84V113.215' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M292.723 113.84V113.215' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M290.73 113.215H294.714' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M292.723 113.84V114.465' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M292.723 113.84V114.465' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M294.715 114.465H290.73' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M351.391 81.34V81.34' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M349.398 81.34H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M351.391 81.34V81.34' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M349.398 81.34H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M410.059 81.34V81.34' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M408.066 81.34H412.054' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M410.059 81.34V81.34' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip1)' d='M408.066 81.34H412.054' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M120.328 206.586H123.563V135.633H120.328ZM178.996 206.586H182.234V81.34H178.996ZM237.664 206.586H240.902V138.387H237.664ZM296.332 206.586H299.57V81.34H296.332ZM355.004 206.586H358.238V81.34H355.004ZM413.672 206.586H416.91V81.34H413.672Z' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M120.328 206.586H123.563V135.633H120.328ZM178.996 206.586H182.234V81.34H178.996ZM237.664 206.586H240.902V138.387H237.664ZM296.332 206.586H299.57V81.34H296.332ZM355.004 206.586H358.238V81.34H355.004ZM413.672 206.586H416.91V81.34H413.672Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M121.945 135.633V135.57' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M121.945 135.633V135.57' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M119.953 135.571H123.938' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M121.945 135.633V135.695' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M121.945 135.633V135.695' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M123.938 135.695H119.953' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M180.613 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M178.621 81.34H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M180.613 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M178.621 81.34H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M239.285 138.387V136.195' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M239.285 138.387V136.195' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M237.293 136.195H241.278' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M239.285 138.387V140.578' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M239.285 138.387V140.578' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M241.274 140.578H237.289' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M297.953 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M295.961 81.34H299.945' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M297.953 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M295.961 81.34H299.945' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M356.621 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M354.629 81.34H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M356.621 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M354.629 81.34H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M415.289 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M413.297 81.34H417.285' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M415.289 81.34V81.34' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip1)' d='M413.297 81.34H417.285' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M125.559 206.586H128.793V139.266H125.559ZM184.227 206.586H187.465V135.695H184.227ZM242.895 206.586H246.133V137.824H242.895ZM301.563 206.586H304.801V97.433H301.563ZM360.234 206.586H363.469V81.34H360.234ZM418.902 206.586H422.141V81.34H418.902Z' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M125.559 206.586H128.793V139.266H125.559ZM184.227 206.586H187.465V135.695H184.227ZM242.895 206.586H246.133V137.824H242.895ZM301.563 206.586H304.801V97.433H301.563ZM360.234 206.586H363.469V81.34H360.234ZM418.902 206.586H422.141V81.34H418.902Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M127.176 139.266V139.203' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M127.176 139.266V139.203' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M125.183 139.203H129.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M127.176 139.266V139.328' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M127.176 139.266V139.328' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M129.168 139.328H125.183' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M185.844 135.695V135.258' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M185.844 135.695V135.258' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M183.851 135.258H187.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M185.844 135.695V136.133' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M185.844 135.695V136.133' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M187.836 136.133H183.851' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M244.516 137.824V137.012' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M244.516 137.824V137.012' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M242.523 137.012H246.508' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M244.516 137.824V138.637' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M244.516 137.824V138.637' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M246.504 138.637H242.519' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M303.184 97.433V95.617' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M303.184 97.433V95.617' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M301.191 95.617H305.175' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M303.184 97.433V99.25' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M303.184 97.433V99.25' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M305.176 99.25H301.191' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M361.852 81.34V81.34' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M359.859 81.34H363.844' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M361.852 81.34V81.34' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M359.859 81.34H363.844' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M420.52 81.34V81.34' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M418.527 81.34H422.515' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M420.52 81.34V81.34' fill='#339999'/>
|
||||
<path clip-path='url(#clip1)' d='M418.527 81.34H422.515' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M130.789 206.586H134.024V136.508H130.789ZM189.457 206.586H192.695V143.023H189.457ZM248.125 206.586H251.363V139.391H248.125ZM306.793 206.586H310.031V134.191H306.793ZM365.465 206.586H368.699V81.34H365.465ZM424.133 206.586H427.371V85.348H424.133Z' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M130.789 206.586H134.024V136.508H130.789ZM189.457 206.586H192.695V143.023H189.457ZM248.125 206.586H251.363V139.391H248.125ZM306.793 206.586H310.031V134.191H306.793ZM365.465 206.586H368.699V81.34H365.465ZM424.133 206.586H427.371V85.348H424.133Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M132.406 136.508V136.445' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M132.406 136.508V136.445' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M130.414 136.445H134.399' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M132.406 136.508V136.57' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M132.406 136.508V136.57' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M134.399 136.571H130.414' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M191.074 143.023V142.582' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M191.074 143.023V142.582' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M189.082 142.582H193.067' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M191.074 143.023V143.461' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M191.074 143.023V143.461' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M193.067 143.461H189.082' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M249.746 139.391V136.383' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M249.746 139.391V136.383' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M247.754 136.383H251.739' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M249.746 139.391V142.394' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M249.746 139.391V142.394' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M251.735 142.395H247.75' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M308.414 134.191V131.875' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M308.414 134.191V131.875' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M306.422 131.875H310.406' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M308.414 134.191V136.508' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M308.414 134.191V136.508' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M310.407 136.508H306.422' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M367.082 81.34V81.34' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M365.09 81.34H369.075' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M367.082 81.34V81.34' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M365.09 81.34H369.075' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M425.75 85.348V72.633' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M425.75 85.348V72.633' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M423.758 72.633H427.746' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M425.75 85.348V98.058' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip1)' d='M425.75 85.348V98.058' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip1)' d='M427.743 98.059H423.758' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(0 -1 1 0 -93.83 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -35.161 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 23.508 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 82.177 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 140.846 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 199.515 252.423)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -88.6 250.983)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -29.93 248.666)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 28.739 256.807)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 87.408 229.879)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 146.077 243.531)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 204.746 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-53' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-56' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -83.369 248.729)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -24.7 251.359)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 33.969 243.218)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 92.638 207.711)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-55' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 151.307 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-54' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 209.976 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -78.139 233.323)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -19.47 249.668)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 39.199 226.497)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 97.868 229.503)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 156.537 241.527)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 215.206 197.503)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-56' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -72.908 250.795)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -14.239 251.547)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 44.43 240.588)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 103.099 248.102)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 161.768 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-54' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 220.437 208.65)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-55' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -67.678 244.032)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -9.009 244.533)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 49.66 223.429)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 108.329 222.302)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 166.998 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-56' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 225.667 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -62.447 244.095)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -3.778 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-54' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 54.891 246.85)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 113.56 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='125.406' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='132.169' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 172.229 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-56' y='186.027'/>
|
||||
<use x='125.406' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-53' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='132.169' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 230.898 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='125.406' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-53' y='186.027'/>
|
||||
<use x='132.169' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -57.217 247.727)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 1.452 244.157)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 60.121 246.286)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 118.79 205.895)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-55' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 177.459 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-52' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-51' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 236.128 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -51.986 244.971)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 6.683 251.484)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 65.352 247.852)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 124.021 242.654)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 182.69 189.8)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='186.027'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='124.23' xlink:href='#g2-50' y='186.027'/>
|
||||
<use x='126.877' xlink:href='#g2-55' y='186.027'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 241.359 193.808)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='186.027'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='186.027'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='186.027'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='186.027'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -126.667 313.708)'>
|
||||
<use x='114.487' xlink:href='#g1-82' y='186.027'/>
|
||||
<use x='120.457' xlink:href='#g1-101' y='186.027'/>
|
||||
<use x='124.553' xlink:href='#g1-108' y='186.027'/>
|
||||
<use x='126.753' xlink:href='#g1-97' y='186.027'/>
|
||||
<use x='131.181' xlink:href='#g1-116' y='186.027'/>
|
||||
<use x='134.509' xlink:href='#g1-105' y='186.027'/>
|
||||
<use x='136.709' xlink:href='#g1-118' y='186.027'/>
|
||||
<use x='140.957' xlink:href='#g1-101' y='186.027'/>
|
||||
<use x='148.124' xlink:href='#g1-116' y='186.027'/>
|
||||
<use x='151.452' xlink:href='#g1-105' y='186.027'/>
|
||||
<use x='153.652' xlink:href='#g1-109' y='186.027'/>
|
||||
<use x='160.972' xlink:href='#g1-101' y='186.027'/>
|
||||
<use x='168.139' xlink:href='#g3-40' y='186.027'/>
|
||||
<use x='171.432' xlink:href='#g3-108' y='186.027'/>
|
||||
<use x='173.453' xlink:href='#g3-111' y='186.027'/>
|
||||
<use x='177.452' xlink:href='#g3-119' y='186.027'/>
|
||||
<use x='183' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='186.764' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='192.479' xlink:href='#g3-105' y='186.027'/>
|
||||
<use x='194.499' xlink:href='#g3-115' y='186.027'/>
|
||||
<use x='200.568' xlink:href='#g3-98' y='186.027'/>
|
||||
<use x='205.176' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='208.94' xlink:href='#g3-116' y='186.027'/>
|
||||
<use x='211.998' xlink:href='#g3-116' y='186.027'/>
|
||||
<use x='215.056' xlink:href='#g3-101' y='186.027'/>
|
||||
<use x='218.819' xlink:href='#g3-114' y='186.027'/>
|
||||
<use x='221.711' xlink:href='#g3-41' y='186.027'/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 75 KiB |
1184
doc/bench-c5-18xlarge-2020-01-20-b.svg
Normal file
1184
doc/bench-c5-18xlarge-2020-01-20-b.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 93 KiB |
756
doc/bench-c5-18xlarge-2020-01-20-rss-a.svg
Normal file
756
doc/bench-c5-18xlarge-2020-01-20-rss-a.svg
Normal file
@ -0,0 +1,756 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- This file was generated by dvisvgm 2.4.2 -->
|
||||
<svg height='193.064pt' version='1.1' viewBox='52.938 51.67 381.624 193.064' width='381.624pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
|
||||
<defs>
|
||||
<clipPath id='clip7'>
|
||||
<path d='M82.148 228.594H434.164V60.828H82.148Z'/>
|
||||
</clipPath>
|
||||
<use id='g3-40' transform='scale(1.143)' xlink:href='#g0-40'/>
|
||||
<use id='g3-41' transform='scale(1.143)' xlink:href='#g0-41'/>
|
||||
<use id='g3-78' transform='scale(1.143)' xlink:href='#g0-78'/>
|
||||
<use id='g3-97' transform='scale(1.143)' xlink:href='#g0-97'/>
|
||||
<use id='g3-98' transform='scale(1.143)' xlink:href='#g0-98'/>
|
||||
<use id='g3-99' transform='scale(1.143)' xlink:href='#g0-99'/>
|
||||
<use id='g3-100' transform='scale(1.143)' xlink:href='#g0-100'/>
|
||||
<use id='g3-101' transform='scale(1.143)' xlink:href='#g0-101'/>
|
||||
<use id='g3-102' transform='scale(1.143)' xlink:href='#g0-102'/>
|
||||
<use id='g3-105' transform='scale(1.143)' xlink:href='#g0-105'/>
|
||||
<use id='g3-108' transform='scale(1.143)' xlink:href='#g0-108'/>
|
||||
<use id='g3-109' transform='scale(1.143)' xlink:href='#g0-109'/>
|
||||
<use id='g3-110' transform='scale(1.143)' xlink:href='#g0-110'/>
|
||||
<use id='g3-111' transform='scale(1.143)' xlink:href='#g0-111'/>
|
||||
<use id='g3-112' transform='scale(1.143)' xlink:href='#g0-112'/>
|
||||
<use id='g3-114' transform='scale(1.143)' xlink:href='#g0-114'/>
|
||||
<use id='g3-115' transform='scale(1.143)' xlink:href='#g0-115'/>
|
||||
<use id='g3-116' transform='scale(1.143)' xlink:href='#g0-116'/>
|
||||
<use id='g3-119' transform='scale(1.143)' xlink:href='#g0-119'/>
|
||||
<path d='M3.891 -2.914C4.806 -3.165 5.452 -3.811 5.452 -4.546C5.452 -5.469 4.411 -6.223 3.129 -6.223H0.87V0H1.704V-2.824H3.138L4.842 0H5.703L3.891 -2.914ZM1.704 -3.407V-5.694H3.022C4.062 -5.694 4.671 -5.192 4.671 -4.546C4.671 -3.963 4.125 -3.407 3.022 -3.407H1.704Z' id='g1-82'/>
|
||||
<path d='M3.694 -2.591C3.694 -3.479 3.04 -4.133 2.152 -4.133C1.569 -4.133 1.139 -3.981 0.708 -3.739L0.762 -3.102C1.21 -3.434 1.65 -3.569 2.143 -3.569C2.645 -3.569 2.95 -3.165 2.95 -2.582V-2.206C1.408 -2.17 0.395 -1.766 0.395 -1.04C0.395 -0.619 0.672 0.099 1.453 0.099C1.632 0.099 2.412 0.081 2.977 -0.341V0H3.694V-2.591ZM2.95 -1.255C2.95 -1.067 2.95 -0.843 2.627 -0.655C2.403 -0.52 2.107 -0.484 1.928 -0.484C1.47 -0.484 1.085 -0.699 1.085 -1.058C1.085 -1.695 2.833 -1.722 2.95 -1.722V-1.255Z' id='g1-97'/>
|
||||
<path d='M3.829 -1.964C3.829 -2.242 3.82 -2.923 3.47 -3.461C3.093 -4.026 2.52 -4.133 2.179 -4.133C1.139 -4.133 0.314 -3.174 0.314 -2.026C0.314 -0.843 1.193 0.099 2.313 0.099C2.744 0.099 3.264 -0.009 3.784 -0.341L3.73 -0.959C3.165 -0.556 2.636 -0.484 2.322 -0.484C1.578 -0.484 1.004 -1.139 0.977 -1.964H3.829ZM1.031 -2.493C1.175 -3.067 1.614 -3.551 2.179 -3.551C2.511 -3.551 3.12 -3.398 3.291 -2.493H1.031Z' id='g1-101'/>
|
||||
<path d='M1.524 -6.133H0.664V-5.272H1.524V-6.133ZM1.453 -3.981H0.735V0H1.453V-3.981Z' id='g1-105'/>
|
||||
<path d='M1.453 -6.223H0.735V0H1.453V-6.223Z' id='g1-108'/>
|
||||
<path d='M1.462 -1.91C1.462 -2.851 2.197 -3.425 3.013 -3.434V-4.08C2.367 -4.071 1.775 -3.748 1.408 -3.219V-4.035H0.744V0H1.462V-1.91Z' id='g1-114'/>
|
||||
<path d='M3.165 -3.847C2.609 -4.098 2.197 -4.133 1.829 -4.133C1.623 -4.133 0.305 -4.133 0.305 -2.95C0.305 -2.52 0.565 -2.251 0.664 -2.152C1.004 -1.856 1.237 -1.811 1.847 -1.695C2.134 -1.641 2.645 -1.542 2.645 -1.085C2.645 -0.502 1.919 -0.502 1.802 -0.502C1.273 -0.502 0.762 -0.681 0.377 -0.95L0.26 -0.296C0.798 -0.009 1.345 0.099 1.802 0.099C2.385 0.099 3.318 -0.09 3.318 -1.157C3.318 -1.47 3.192 -1.784 2.878 -2.053C2.573 -2.313 2.304 -2.367 1.748 -2.475C1.426 -2.537 0.977 -2.618 0.977 -3.04C0.977 -3.569 1.614 -3.569 1.748 -3.569C2.403 -3.569 2.789 -3.362 3.049 -3.219L3.165 -3.847Z' id='g1-115'/>
|
||||
<path d='M1.623 -3.425H2.914V-3.981H1.623V-5.12H0.959V-3.981H0.17V-3.425H0.933V-1.13C0.933 -0.601 1.049 0.099 1.704 0.099C2.098 0.099 2.564 0.018 3.067 -0.233L2.914 -0.798C2.681 -0.619 2.367 -0.511 2.089 -0.511C1.739 -0.511 1.623 -0.825 1.623 -1.291V-3.425Z' id='g1-116'/>
|
||||
<path d='M4.116 -3.981H3.407L2.699 -2.161C2.52 -1.695 2.188 -0.825 2.143 -0.493H2.125C2.107 -0.646 2.08 -0.816 1.587 -2.107C1.318 -2.833 0.879 -3.927 0.861 -3.981H0.126L1.704 0H2.537L4.116 -3.981Z' id='g1-118'/>
|
||||
<use id='g2-46' transform='scale(0.714)' xlink:href='#g0-46'/>
|
||||
<use id='g2-48' transform='scale(0.714)' xlink:href='#g0-48'/>
|
||||
<use id='g2-49' transform='scale(0.714)' xlink:href='#g0-49'/>
|
||||
<use id='g2-50' transform='scale(0.714)' xlink:href='#g0-50'/>
|
||||
<use id='g2-51' transform='scale(0.714)' xlink:href='#g0-51'/>
|
||||
<use id='g2-52' transform='scale(0.714)' xlink:href='#g0-52'/>
|
||||
<use id='g2-53' transform='scale(0.714)' xlink:href='#g0-53'/>
|
||||
<use id='g2-54' transform='scale(0.714)' xlink:href='#g0-54'/>
|
||||
<use id='g2-55' transform='scale(0.714)' xlink:href='#g0-55'/>
|
||||
<use id='g2-56' transform='scale(0.714)' xlink:href='#g0-56'/>
|
||||
<use id='g2-57' transform='scale(0.714)' xlink:href='#g0-57'/>
|
||||
<use id='g2-120' transform='scale(0.714)' xlink:href='#g0-120'/>
|
||||
<path d='M2.127 -5.23C2.008 -5.23 1.995 -5.23 1.911 -5.154C1.032 -4.387 0.586 -3.145 0.586 -1.743C0.586 -0.425 0.983 0.844 1.904 1.653C1.995 1.743 2.008 1.743 2.127 1.743H2.462C2.441 1.73 1.764 1.151 1.444 0.063C1.276 -0.481 1.193 -1.053 1.193 -1.743C1.193 -4.156 2.322 -5.112 2.462 -5.23H2.127Z' id='g0-40'/>
|
||||
<path d='M0.746 1.743C0.865 1.743 0.879 1.743 0.962 1.667C1.841 0.9 2.287 -0.342 2.287 -1.743C2.287 -3.062 1.89 -4.331 0.969 -5.14C0.879 -5.23 0.865 -5.23 0.746 -5.23H0.411C0.432 -5.216 1.109 -4.638 1.43 -3.55C1.597 -3.006 1.681 -2.434 1.681 -1.743C1.681 0.669 0.551 1.625 0.411 1.743H0.746Z' id='g0-41'/>
|
||||
<path d='M1.339 -0.628H0.711V0H1.339V-0.628Z' id='g0-46'/>
|
||||
<path d='M3.403 -2.267C3.403 -2.601 3.403 -3.417 3.075 -3.989C2.72 -4.617 2.183 -4.721 1.848 -4.721C1.534 -4.721 0.99 -4.624 0.642 -4.024C0.307 -3.466 0.293 -2.706 0.293 -2.267C0.293 -1.75 0.321 -1.116 0.614 -0.586C0.921 -0.021 1.437 0.146 1.848 0.146C2.545 0.146 2.929 -0.258 3.138 -0.697C3.382 -1.193 3.403 -1.834 3.403 -2.267ZM1.848 -0.314C1.555 -0.314 1.22 -0.481 1.046 -0.983C0.907 -1.409 0.9 -1.848 0.9 -2.357C0.9 -2.999 0.9 -4.261 1.848 -4.261S2.797 -2.999 2.797 -2.357C2.797 -1.897 2.797 -1.374 2.629 -0.928C2.434 -0.425 2.078 -0.314 1.848 -0.314Z' id='g0-48'/>
|
||||
<path d='M2.239 -4.721H2.085C1.632 -4.303 1.06 -4.275 0.642 -4.261V-3.822C0.914 -3.829 1.262 -3.843 1.611 -3.982V-0.439H0.683V0H3.166V-0.439H2.239V-4.721Z' id='g0-49'/>
|
||||
<path d='M1.974 -0.537C1.89 -0.537 1.806 -0.53 1.723 -0.53H0.928L2.008 -1.485C2.134 -1.597 2.476 -1.855 2.608 -1.967C2.915 -2.246 3.327 -2.608 3.327 -3.215C3.327 -4.003 2.741 -4.721 1.743 -4.721C1.004 -4.721 0.544 -4.324 0.307 -3.612L0.635 -3.201C0.795 -3.787 1.039 -4.24 1.646 -4.24C2.232 -4.24 2.678 -3.829 2.678 -3.201C2.678 -2.622 2.336 -2.294 1.918 -1.897C1.778 -1.757 1.402 -1.444 1.255 -1.304C1.053 -1.123 0.572 -0.656 0.37 -0.481V0H3.327V-0.537H1.974Z' id='g0-50'/>
|
||||
<path d='M0.697 -3.578C0.983 -4.135 1.485 -4.289 1.82 -4.289C2.232 -4.289 2.538 -4.052 2.538 -3.654C2.538 -3.285 2.287 -2.831 1.757 -2.741C1.723 -2.734 1.695 -2.734 1.234 -2.699V-2.239H1.778C2.441 -2.239 2.685 -1.716 2.685 -1.276C2.685 -0.732 2.35 -0.314 1.806 -0.314C1.311 -0.314 0.746 -0.551 0.398 -0.997L0.307 -0.544C0.711 -0.091 1.276 0.146 1.82 0.146C2.734 0.146 3.389 -0.537 3.389 -1.269C3.389 -1.841 2.929 -2.301 2.378 -2.462C2.908 -2.734 3.18 -3.201 3.18 -3.654C3.18 -4.247 2.573 -4.721 1.827 -4.721C1.213 -4.721 0.704 -4.4 0.411 -3.982L0.697 -3.578Z' id='g0-51'/>
|
||||
<path d='M2.762 -1.165H3.487V-1.625H2.762V-4.575H2.071L0.209 -1.625V-1.165H2.162V0H2.762V-1.165ZM0.802 -1.625C1.011 -1.953 2.211 -3.815 2.211 -4.233V-1.625H0.802Z' id='g0-52'/>
|
||||
<path d='M1.144 -4.094H3.075V-4.575H0.586V-1.967H1.095C1.262 -2.343 1.59 -2.511 1.904 -2.511C2.19 -2.511 2.622 -2.315 2.622 -1.43C2.622 -0.516 2.043 -0.314 1.688 -0.314C1.227 -0.314 0.781 -0.558 0.544 -0.955L0.279 -0.537C0.621 -0.112 1.137 0.146 1.688 0.146C2.608 0.146 3.327 -0.565 3.327 -1.416C3.327 -2.28 2.685 -2.971 1.918 -2.971C1.618 -2.971 1.353 -2.866 1.144 -2.692V-4.094Z' id='g0-53'/>
|
||||
<path d='M3.062 -4.582C2.685 -4.721 2.42 -4.721 2.287 -4.721C1.227 -4.721 0.307 -3.724 0.307 -2.253C0.307 -0.363 1.158 0.146 1.862 0.146C2.427 0.146 2.72 -0.119 2.936 -0.342C3.382 -0.816 3.389 -1.311 3.389 -1.555C3.389 -2.469 2.894 -3.229 2.218 -3.229C1.534 -3.229 1.165 -2.873 0.962 -2.671C1.053 -3.626 1.541 -4.289 2.294 -4.289C2.434 -4.289 2.713 -4.275 3.062 -4.142V-4.582ZM0.969 -1.534C0.969 -1.576 0.969 -1.681 0.976 -1.716C0.976 -2.19 1.276 -2.769 1.897 -2.769C2.748 -2.769 2.748 -1.792 2.748 -1.555C2.748 -1.29 2.748 -0.997 2.559 -0.704C2.392 -0.453 2.183 -0.314 1.862 -0.314C1.123 -0.314 1.004 -1.227 0.969 -1.534Z' id='g0-54'/>
|
||||
<path d='M1.723 -4.038C1.806 -4.038 1.89 -4.045 1.974 -4.045H2.852C1.792 -3.006 1.116 -1.548 1.116 0.07H1.771C1.771 -1.967 2.762 -3.431 3.389 -4.087V-4.575H0.307V-4.038H1.723Z' id='g0-55'/>
|
||||
<path d='M2.385 -2.469C2.845 -2.615 3.285 -2.985 3.285 -3.501C3.285 -4.135 2.678 -4.721 1.848 -4.721S0.411 -4.135 0.411 -3.501C0.411 -2.978 0.865 -2.608 1.311 -2.469C0.697 -2.28 0.307 -1.806 0.307 -1.269C0.307 -0.523 0.969 0.146 1.848 0.146S3.389 -0.523 3.389 -1.269C3.389 -1.806 2.992 -2.28 2.385 -2.469ZM1.848 -2.699C1.353 -2.699 0.948 -2.985 0.948 -3.494C0.948 -3.94 1.262 -4.289 1.848 -4.289C2.427 -4.289 2.748 -3.94 2.748 -3.494C2.748 -2.999 2.357 -2.699 1.848 -2.699ZM1.848 -0.314C1.367 -0.314 0.941 -0.621 0.941 -1.276C0.941 -1.904 1.346 -2.239 1.848 -2.239S2.755 -1.897 2.755 -1.276C2.755 -0.621 2.322 -0.314 1.848 -0.314Z' id='g0-56'/>
|
||||
<path d='M0.537 -0.174C0.879 0.077 1.193 0.146 1.52 0.146C2.497 0.146 3.389 -0.837 3.389 -2.336C3.389 -4.24 2.545 -4.721 1.876 -4.721C1.255 -4.721 0.969 -4.428 0.767 -4.226C0.321 -3.773 0.307 -3.292 0.307 -3.02C0.307 -2.12 0.795 -1.346 1.478 -1.346C2.267 -1.346 2.699 -1.869 2.734 -1.911C2.636 -0.802 2.092 -0.314 1.52 -0.314C1.158 -0.314 0.934 -0.446 0.774 -0.579L0.537 -0.174ZM2.713 -3.027C2.72 -2.985 2.72 -2.915 2.72 -2.873C2.72 -2.357 2.406 -1.806 1.799 -1.806C1.534 -1.806 1.325 -1.883 1.144 -2.169C0.962 -2.441 0.948 -2.706 0.948 -3.02C0.948 -3.292 0.948 -3.605 1.165 -3.912C1.311 -4.122 1.52 -4.289 1.869 -4.289C2.545 -4.289 2.692 -3.473 2.713 -3.027Z' id='g0-57'/>
|
||||
<path d='M1.646 -4.84H0.697V0H1.283V-4.289H1.29L3.578 0H4.526V-4.84H3.94V-0.551H3.933L1.646 -4.84Z' id='g0-78'/>
|
||||
<path d='M2.971 -2.008C2.971 -2.72 2.427 -3.201 1.736 -3.201C1.297 -3.201 0.962 -3.11 0.572 -2.901L0.614 -2.392C0.844 -2.545 1.186 -2.755 1.736 -2.755C2.043 -2.755 2.364 -2.525 2.364 -2.001V-1.723C1.332 -1.688 0.314 -1.471 0.314 -0.823C0.314 -0.474 0.551 0.07 1.165 0.07C1.465 0.07 2.015 0.007 2.385 -0.265V0H2.971V-2.008ZM2.364 -0.99C2.364 -0.851 2.364 -0.669 2.12 -0.523C1.897 -0.398 1.625 -0.391 1.548 -0.391C1.165 -0.391 0.872 -0.565 0.872 -0.83C0.872 -1.276 2.05 -1.318 2.364 -1.332V-0.99Z' id='g0-97'/>
|
||||
<path d='M1.179 -4.84H0.593V0H1.2V-0.328C1.353 -0.195 1.688 0.07 2.197 0.07C2.957 0.07 3.571 -0.642 3.571 -1.555C3.571 -2.399 3.089 -3.166 2.392 -3.166C1.953 -3.166 1.527 -3.027 1.179 -2.769V-4.84ZM1.2 -2.197C1.2 -2.308 1.2 -2.392 1.444 -2.552C1.548 -2.615 1.736 -2.706 1.974 -2.706C2.441 -2.706 2.964 -2.392 2.964 -1.555C2.964 -0.704 2.385 -0.391 1.897 -0.391C1.639 -0.391 1.395 -0.509 1.2 -0.823V-2.197Z' id='g0-98'/>
|
||||
<path d='M3.034 -0.76C2.685 -0.537 2.308 -0.411 1.876 -0.411C1.234 -0.411 0.858 -0.928 0.858 -1.555C0.858 -2.092 1.137 -2.72 1.897 -2.72C2.371 -2.72 2.594 -2.622 2.95 -2.399L3.041 -2.901C2.622 -3.11 2.441 -3.201 1.897 -3.201C0.851 -3.201 0.251 -2.357 0.251 -1.548C0.251 -0.697 0.921 0.07 1.869 0.07C2.357 0.07 2.776 -0.077 3.075 -0.251L3.034 -0.76Z' id='g0-99'/>
|
||||
<path d='M3.229 -4.84H2.643V-2.797C2.197 -3.124 1.743 -3.166 1.541 -3.166C0.809 -3.166 0.251 -2.434 0.251 -1.548S0.802 0.07 1.52 0.07C1.953 0.07 2.357 -0.126 2.622 -0.363V0H3.229V-4.84ZM2.622 -0.865C2.448 -0.579 2.183 -0.391 1.848 -0.391C1.36 -0.391 0.858 -0.732 0.858 -1.541C0.858 -2.413 1.451 -2.706 1.925 -2.706C2.204 -2.706 2.441 -2.587 2.622 -2.35V-0.865Z' id='g0-100'/>
|
||||
<path d='M2.999 -0.76C2.608 -0.481 2.169 -0.391 1.869 -0.391C1.262 -0.391 0.802 -0.886 0.781 -1.527H3.068C3.068 -1.848 3.034 -2.315 2.762 -2.713C2.511 -3.068 2.092 -3.201 1.75 -3.201C0.9 -3.201 0.244 -2.455 0.244 -1.569C0.244 -0.676 0.941 0.07 1.862 0.07C2.267 0.07 2.685 -0.049 3.041 -0.265L2.999 -0.76ZM0.83 -1.946C0.99 -2.504 1.402 -2.741 1.75 -2.741C2.057 -2.741 2.511 -2.594 2.643 -1.946H0.83Z' id='g0-101'/>
|
||||
<path d='M1.325 -2.657H2.12V-3.096H1.304V-3.898C1.304 -4.38 1.743 -4.449 1.974 -4.449C2.12 -4.449 2.308 -4.428 2.566 -4.331V-4.84C2.385 -4.882 2.169 -4.91 1.981 -4.91C1.262 -4.91 0.739 -4.394 0.739 -3.703V-3.096H0.202V-2.657H0.739V0H1.325V-2.657Z' id='g0-102'/>
|
||||
<path d='M1.227 -4.784H0.523V-4.08H1.227V-4.784ZM1.172 -3.096H0.586V0H1.172V-3.096Z' id='g0-105'/>
|
||||
<path d='M1.172 -4.84H0.586V0H1.172V-4.84Z' id='g0-108'/>
|
||||
<path d='M5.3 -2.064C5.3 -2.608 5.14 -3.166 4.282 -3.166C3.696 -3.166 3.333 -2.824 3.166 -2.601C3.096 -2.79 2.922 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-1.695C3.243 -2.155 3.438 -2.706 3.975 -2.706C4.693 -2.706 4.693 -2.218 4.693 -2.015V0H5.3V-2.064Z' id='g0-109'/>
|
||||
<path d='M3.243 -2.064C3.243 -2.608 3.082 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-2.064Z' id='g0-110'/>
|
||||
<path d='M3.487 -1.527C3.487 -2.448 2.755 -3.201 1.848 -3.201S0.209 -2.441 0.209 -1.527C0.209 -0.642 0.948 0.07 1.848 0.07C2.755 0.07 3.487 -0.642 3.487 -1.527ZM1.848 -0.411C1.297 -0.411 0.816 -0.816 0.816 -1.604S1.332 -2.741 1.848 -2.741C2.371 -2.741 2.88 -2.378 2.88 -1.604C2.88 -0.809 2.385 -0.411 1.848 -0.411Z' id='g0-111'/>
|
||||
<path d='M1.2 -0.328C1.569 0.007 1.967 0.07 2.204 0.07C2.943 0.07 3.571 -0.635 3.571 -1.555C3.571 -2.392 3.11 -3.166 2.42 -3.166C2.106 -3.166 1.583 -3.075 1.179 -2.762V-3.096H0.593V1.353H1.2V-0.328ZM1.2 -2.315C1.36 -2.511 1.632 -2.685 1.967 -2.685C2.525 -2.685 2.964 -2.169 2.964 -1.555C2.964 -0.865 2.441 -0.391 1.897 -0.391C1.792 -0.391 1.618 -0.404 1.437 -0.551C1.227 -0.711 1.2 -0.816 1.2 -0.948V-2.315Z' id='g0-112'/>
|
||||
<path d='M1.179 -1.485C1.179 -2.239 1.806 -2.643 2.42 -2.65V-3.166C1.834 -3.159 1.409 -2.873 1.13 -2.504V-3.145H0.593V0H1.179V-1.485Z' id='g0-114'/>
|
||||
<path d='M2.545 -2.985C2.071 -3.18 1.723 -3.201 1.471 -3.201C1.297 -3.201 0.244 -3.201 0.244 -2.273C0.244 -1.946 0.425 -1.764 0.516 -1.681C0.76 -1.437 1.053 -1.381 1.423 -1.311C1.75 -1.248 2.127 -1.179 2.127 -0.844C2.127 -0.404 1.548 -0.404 1.451 -0.404C1.004 -0.404 0.586 -0.565 0.307 -0.76L0.209 -0.237C0.446 -0.119 0.872 0.07 1.451 0.07C1.764 0.07 2.071 0.021 2.329 -0.167C2.587 -0.363 2.671 -0.669 2.671 -0.907C2.671 -1.032 2.657 -1.304 2.364 -1.569C2.106 -1.799 1.855 -1.848 1.52 -1.911C1.109 -1.988 0.788 -2.05 0.788 -2.357C0.788 -2.755 1.297 -2.755 1.402 -2.755C1.799 -2.755 2.106 -2.671 2.455 -2.49L2.545 -2.985Z' id='g0-115'/>
|
||||
<path d='M1.311 -2.657H2.343V-3.096H1.311V-3.982H0.774V-3.096H0.139V-2.657H0.753V-0.893C0.753 -0.425 0.872 0.07 1.374 0.07S2.26 -0.091 2.469 -0.188L2.35 -0.635C2.12 -0.467 1.876 -0.411 1.681 -0.411C1.388 -0.411 1.311 -0.697 1.311 -1.018V-2.657Z' id='g0-116'/>
|
||||
<path d='M4.951 -3.096H4.407C4.345 -2.901 3.954 -1.723 3.738 -0.997C3.682 -0.795 3.612 -0.572 3.592 -0.411H3.585C3.543 -0.697 3.299 -1.451 3.285 -1.499L2.769 -3.096H2.239C2.036 -2.497 1.513 -0.934 1.458 -0.425H1.451C1.395 -0.921 0.879 -2.462 0.767 -2.797C0.711 -2.964 0.711 -2.978 0.676 -3.096H0.105L1.123 0H1.709C1.716 -0.028 1.904 -0.579 2.148 -1.353C2.253 -1.695 2.462 -2.364 2.497 -2.671L2.504 -2.678C2.518 -2.532 2.559 -2.378 2.608 -2.204S2.706 -1.841 2.755 -1.681L3.292 0H3.933L4.951 -3.096Z' id='g0-119'/>
|
||||
<path d='M1.932 -1.597L3.285 -3.096H2.671L1.681 -1.953L0.669 -3.096H0.042L1.437 -1.597L0 0H0.621L1.681 -1.311L2.783 0H3.41L1.932 -1.597Z' id='g0-120'/>
|
||||
</defs>
|
||||
<g id='page7'>
|
||||
<path d='M140.82 237.449V228.594M199.488 237.449V228.594M258.156 237.449V228.594M316.824 237.449V228.594M375.496 237.449V228.594M140.82 51.969V60.828M199.488 51.969V60.828M258.156 51.969V60.828M316.824 51.969V60.828M375.496 51.969V60.828' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M111.484 232.844V228.594M170.152 232.844V228.594M228.824 232.844V228.594M287.492 232.844V228.594M346.16 232.844V228.594M404.828 232.844V228.594M111.484 56.574V60.828M170.152 56.574V60.828M228.824 56.574V60.828M287.492 56.574V60.828M346.16 56.574V60.828M404.828 56.574V60.828' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 228.594H86.402M82.148 195.039H86.402M82.148 161.484H86.402M82.148 127.934H86.402M82.148 94.379H86.402M82.148 60.828H86.402M434.164 228.594H429.91M434.164 195.039H429.91M434.164 161.484H429.91M434.164 127.934H429.91M434.164 94.379H429.91M434.164 60.828H429.91' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 228.594V60.828H434.164V228.594H82.148Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(1 0 0 1 -11.54 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-99' y='208.035'/>
|
||||
<use x='118.25' xlink:href='#g3-102' y='208.035'/>
|
||||
<use x='120.838' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='123.73' xlink:href='#g3-97' y='208.035'/>
|
||||
<use x='127.798' xlink:href='#g3-99' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 45.565 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='208.035'/>
|
||||
<use x='116.507' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='120.271' xlink:href='#g3-97' y='208.035'/>
|
||||
<use x='124.339' xlink:href='#g3-110' y='208.035'/>
|
||||
<use x='128.711' xlink:href='#g3-78' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 106.188 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='117.379' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='121.142' xlink:href='#g3-100' y='208.035'/>
|
||||
<use x='125.515' xlink:href='#g3-105' y='208.035'/>
|
||||
<use x='127.535' xlink:href='#g3-115' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 159.716 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='208.035'/>
|
||||
<use x='116.507' xlink:href='#g3-97' y='208.035'/>
|
||||
<use x='120.34' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='123.232' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='126.478' xlink:href='#g3-111' y='208.035'/>
|
||||
<use x='130.712' xlink:href='#g3-110' y='208.035'/>
|
||||
<use x='135.085' xlink:href='#g3-78' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 215.596 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-109' y='208.035'/>
|
||||
<use x='121.211' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='124.458' xlink:href='#g3-116' y='208.035'/>
|
||||
<use x='127.516' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='130.408' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='134.171' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='137.418' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='140.664' xlink:href='#g3-78' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 277.158 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='117.379' xlink:href='#g3-112' y='208.035'/>
|
||||
<use x='121.751' xlink:href='#g3-116' y='208.035'/>
|
||||
<use x='124.809' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='128.573' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='131.819' xlink:href='#g3-116' y='208.035'/>
|
||||
<use x='134.877' xlink:href='#g3-78' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -40.942 22.192)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -11.361)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -44.915)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -78.468)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -112.021)'>
|
||||
<use x='114.487' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -145.574)'>
|
||||
<use x='114.487' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='208.035'/>
|
||||
</g>
|
||||
<path clip-path='url(#clip7)' d='M82.148 161.484H434.164' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M88.945 228.594H92.18V161.484H88.945ZM147.613 228.594H150.852V161.484H147.613ZM206.281 228.594H209.52V161.484H206.281ZM264.949 228.594H268.188V161.484H264.949ZM323.621 228.594H326.859V161.484H323.621ZM382.289 228.594H385.527V161.484H382.289Z' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M88.945 228.594H92.18V161.484H88.945ZM147.613 228.594H150.852V161.484H147.613ZM206.281 228.594H209.52V161.484H206.281ZM264.949 228.594H268.188V161.484H264.949ZM323.621 228.594H326.859V161.484H323.621ZM382.289 228.594H385.527V161.484H382.289Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M90.563 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M88.57 161.484H92.555' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M90.563 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M88.57 161.484H92.555' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M149.231 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M147.238 161.484H151.223' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M149.231 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M147.238 161.484H151.223' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M207.902 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M205.906 161.484H209.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M207.902 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M205.906 161.484H209.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M266.57 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M264.578 161.484H268.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M266.57 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M264.578 161.484H268.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M325.238 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M323.246 161.484H327.23' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M325.238 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M323.246 161.484H327.23' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M383.906 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M381.914 161.484H385.898' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M383.906 161.484V161.484' fill='#ffffff'/>
|
||||
<path clip-path='url(#clip7)' d='M381.914 161.484H385.898' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M94.176 228.594H97.41V74.719H94.176ZM152.844 228.594H156.082V172.559H152.844ZM211.512 228.594H214.75V145.852H211.512ZM270.18 228.594H273.418V154.773H270.18ZM328.852 228.594H332.09V193.43H328.852ZM387.52 228.594H390.758V191.148H387.52Z' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M94.176 228.594H97.41V74.719H94.176ZM152.844 228.594H156.082V172.559H152.844ZM211.512 228.594H214.75V145.852H211.512ZM270.18 228.594H273.418V154.773H270.18ZM328.852 228.594H332.09V193.43H328.852ZM387.52 228.594H390.758V191.148H387.52Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M95.793 74.719V74.719' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M93.801 74.719H97.785' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M95.793 74.719V74.719' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M93.801 74.719H97.785' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M154.461 172.559V172.559' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M152.469 172.558H156.454' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M154.461 172.559V172.559' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M152.469 172.558H156.454' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M213.133 145.852V145.852' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M211.137 145.851H215.125' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M213.133 145.852V145.852' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M211.137 145.851H215.125' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M271.801 154.773V154.773' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M269.809 154.773H273.793' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M271.801 154.773V154.773' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M269.809 154.773H273.793' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M330.469 193.43V193.43' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M328.477 193.429H332.461' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M330.469 193.43V193.43' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M328.477 193.429H332.461' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M389.137 191.148V191.148' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M387.145 191.149H391.129' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M389.137 191.148V191.148' fill='#f0e0f0'/>
|
||||
<path clip-path='url(#clip7)' d='M387.145 191.149H391.129' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M99.406 228.594H102.641V138.133H99.406ZM158.074 228.594H161.313V162.961H158.074ZM216.742 228.594H219.981V157.797H216.742ZM275.41 228.594H278.649V141.02H275.41ZM334.082 228.594H337.32V191.816H334.082ZM392.75 228.594H395.988V179.871H392.75Z' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M99.406 228.594H102.641V138.133H99.406ZM158.074 228.594H161.313V162.961H158.074ZM216.742 228.594H219.981V157.797H216.742ZM275.41 228.594H278.649V141.02H275.41ZM334.082 228.594H337.32V191.816H334.082ZM392.75 228.594H395.988V179.871H392.75Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M101.024 138.133V138.133' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M99.031 138.133H103.016' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M101.024 138.133V138.133' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M99.031 138.133H103.016' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M159.691 162.961V162.961' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M157.699 162.961H161.684' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M159.691 162.961V162.961' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M157.699 162.961H161.684' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M218.363 157.797V157.797' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M216.367 157.797H220.355' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M218.363 157.797V157.797' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M216.367 157.797H220.355' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M277.031 141.02V141.02' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M275.039 141.02H279.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M277.031 141.02V141.02' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M275.039 141.02H279.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M335.699 191.816V191.816' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M333.707 191.816H337.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M335.699 191.816V191.816' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M333.707 191.816H337.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M394.367 179.871V179.871' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M392.375 179.871H396.359' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M394.367 179.871V179.871' fill='#e1c2e1'/>
|
||||
<path clip-path='url(#clip7)' d='M392.375 179.871H396.359' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M104.637 228.594H107.871V140.883H104.637ZM163.305 228.594H166.543V152.695H163.305ZM221.973 228.594H225.211V115.184H221.973ZM280.641 228.594H283.879V167.793H280.641ZM339.313 228.594H342.551V189.738H339.313ZM397.981 228.594H401.219V194.367H397.981Z' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M104.637 228.594H107.871V140.883H104.637ZM163.305 228.594H166.543V152.695H163.305ZM221.973 228.594H225.211V115.184H221.973ZM280.641 228.594H283.879V167.793H280.641ZM339.313 228.594H342.551V189.738H339.313ZM397.981 228.594H401.219V194.367H397.981Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M106.254 140.883V140.883' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M104.261 140.882H108.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M106.254 140.883V140.883' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M104.261 140.882H108.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M164.922 152.695V152.695' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M162.929 152.695H166.914' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M164.922 152.695V152.695' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M162.929 152.695H166.914' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M223.594 115.184V115.184' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M221.597 115.184H225.585' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M223.594 115.184V115.184' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M221.597 115.184H225.585' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M282.262 167.793V167.793' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M280.269 167.793H284.253' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M282.262 167.793V167.793' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M280.269 167.793H284.253' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M340.93 189.738V189.738' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M338.937 189.739H342.921' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M340.93 189.738V189.738' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M338.937 189.739H342.921' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M399.598 194.367V194.367' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M397.605 194.367H401.589' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M399.598 194.367V194.367' fill='#d1a3d1'/>
|
||||
<path clip-path='url(#clip7)' d='M397.605 194.367H401.589' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M109.867 228.594H113.102V163.031H109.867ZM168.535 228.594H171.774V157.191H168.535ZM227.203 228.594H230.442V142.094H227.203ZM285.871 228.594H289.109V150.414H285.871ZM344.543 228.594H347.781V150.949H344.543ZM403.211 228.594H406.449V103.105H403.211Z' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M109.867 228.594H113.102V163.031H109.867ZM168.535 228.594H171.774V157.191H168.535ZM227.203 228.594H230.442V142.094H227.203ZM285.871 228.594H289.109V150.414H285.871ZM344.543 228.594H347.781V150.949H344.543ZM403.211 228.594H406.449V103.105H403.211Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M111.484 163.031V163.031' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M109.492 163.031H113.477' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M111.484 163.031V163.031' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M109.492 163.031H113.477' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M170.152 157.191V157.191' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M168.16 157.191H172.145' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M170.152 157.191V157.191' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M168.16 157.191H172.145' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M228.824 142.094V142.094' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M226.828 142.093H230.816' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M228.824 142.094V142.094' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M226.828 142.093H230.816' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M287.492 150.414V150.414' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M285.5 150.414H289.484' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M287.492 150.414V150.414' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M285.5 150.414H289.484' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M346.16 150.949V150.949' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M344.168 150.949H348.152' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M346.16 150.949V150.949' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M344.168 150.949H348.152' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M404.828 103.105V103.105' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M402.836 103.106H406.82' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M404.828 103.105V103.105' fill='#c285c2'/>
|
||||
<path clip-path='url(#clip7)' d='M402.836 103.106H406.82' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M115.098 228.594H118.332V133.906H115.098ZM173.766 228.594H177.004V148.133H173.766ZM232.434 228.594H235.672V144.91H232.434ZM291.102 228.594H294.34V160.48H291.102ZM349.774 228.594H353.012V168.801H349.774ZM408.442 228.594H411.68V181.484H408.442Z' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M115.098 228.594H118.332V133.906H115.098ZM173.766 228.594H177.004V148.133H173.766ZM232.434 228.594H235.672V144.91H232.434ZM291.102 228.594H294.34V160.48H291.102ZM349.774 228.594H353.012V168.801H349.774ZM408.442 228.594H411.68V181.484H408.442Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M116.715 133.906V133.906' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M114.722 133.906H118.707' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M116.715 133.906V133.906' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M114.722 133.906H118.707' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M175.383 148.133V148.133' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M173.39 148.133H177.375' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M175.383 148.133V148.133' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M173.39 148.133H177.375' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M234.055 144.91V144.91' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M232.058 144.91H236.046' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M234.055 144.91V144.91' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M232.058 144.91H236.046' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M292.723 160.48V160.48' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M290.73 160.48H294.714' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M292.723 160.48V160.48' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M290.73 160.48H294.714' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M351.391 168.801V168.801' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M349.398 168.801H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M351.391 168.801V168.801' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M349.398 168.801H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M410.059 181.484V181.484' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M408.066 181.485H412.05' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M410.059 181.484V181.484' fill='#b366b3'/>
|
||||
<path clip-path='url(#clip7)' d='M408.066 181.485H412.05' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M120.328 228.594H123.563V140.48H120.328ZM178.996 228.594H182.234V159.473H178.996ZM237.664 228.594H240.902V159.406H237.664ZM296.332 228.594H299.57V157.797H296.332ZM355.004 228.594H358.238V172.355H355.004ZM413.672 228.594H416.91V184.637H413.672Z' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M120.328 228.594H123.563V140.48H120.328ZM178.996 228.594H182.234V159.473H178.996ZM237.664 228.594H240.902V159.406H237.664ZM296.332 228.594H299.57V157.797H296.332ZM355.004 228.594H358.238V172.355H355.004ZM413.672 228.594H416.91V184.637H413.672Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M121.945 140.48V140.48' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M119.953 140.481H123.938' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M121.945 140.48V140.48' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M119.953 140.481H123.938' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M180.613 159.473V159.473' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M178.621 159.473H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M180.613 159.473V159.473' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M178.621 159.473H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M239.285 159.406V159.406' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M237.289 159.407H241.274' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M239.285 159.406V159.406' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M237.289 159.407H241.274' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M297.953 157.797V157.797' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M295.961 157.797H299.945' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M297.953 157.797V157.797' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M295.961 157.797H299.945' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M356.621 172.355V172.355' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M354.629 172.355H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M356.621 172.355V172.355' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M354.629 172.355H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M415.289 184.637V184.637' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M413.297 184.637H417.281' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M415.289 184.637V184.637' fill='#a447a4'/>
|
||||
<path clip-path='url(#clip7)' d='M413.297 184.637H417.281' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M125.559 228.594H128.793V163.098H125.559ZM184.227 228.594H187.465V151.824H184.227ZM242.895 228.594H246.133V161.082H242.895ZM301.563 228.594H304.801V167.457H301.563ZM360.234 228.594H363.469V168.195H360.234ZM418.902 228.594H422.141V199.332H418.902Z' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M125.559 228.594H128.793V163.098H125.559ZM184.227 228.594H187.465V151.824H184.227ZM242.895 228.594H246.133V161.082H242.895ZM301.563 228.594H304.801V167.457H301.563ZM360.234 228.594H363.469V168.195H360.234ZM418.902 228.594H422.141V199.332H418.902Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M127.176 163.098V163.098' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M125.183 163.097H129.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M127.176 163.098V163.098' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M125.183 163.097H129.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M185.844 151.824V151.824' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M183.851 151.825H187.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M185.844 151.824V151.824' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M183.851 151.825H187.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M244.516 161.082V161.082' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M242.519 161.082H246.504' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M244.516 161.082V161.082' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M242.519 161.082H246.504' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M303.184 167.457V167.457' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M301.191 167.457H305.175' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M303.184 167.457V167.457' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M301.191 167.457H305.175' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M361.852 168.195V168.195' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M359.859 168.196H363.843' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M361.852 168.195V168.195' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M359.859 168.196H363.843' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M420.52 199.332V199.332' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M418.527 199.332H422.511' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M420.52 199.332V199.332' fill='#942994'/>
|
||||
<path clip-path='url(#clip7)' d='M418.527 199.332H422.511' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M130.789 228.594H134.024V157.996H130.789ZM189.457 228.594H192.695V153.969H189.457ZM248.125 228.594H251.363V154.305H248.125ZM306.793 228.594H310.031V122.633H306.793ZM365.465 228.594H368.699V165.98H365.465ZM424.133 228.594H427.371V150.211H424.133Z' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M130.789 228.594H134.024V157.996H130.789ZM189.457 228.594H192.695V153.969H189.457ZM248.125 228.594H251.363V154.305H248.125ZM306.793 228.594H310.031V122.633H306.793ZM365.465 228.594H368.699V165.98H365.465ZM424.133 228.594H427.371V150.211H424.133Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M132.406 157.996V157.996' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M130.414 157.996H134.399' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M132.406 157.996V157.996' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M130.414 157.996H134.399' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M191.074 153.969V153.969' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M189.082 153.969H193.067' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M191.074 153.969V153.969' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M189.082 153.969H193.067' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M249.746 154.305V154.305' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M247.75 154.305H251.735' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M249.746 154.305V154.305' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M247.75 154.305H251.735' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M308.414 122.633V122.633' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M306.422 122.633H310.407' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M308.414 122.633V122.633' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M306.422 122.633H310.407' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M367.082 165.98V165.98' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M365.09 165.98H369.074' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M367.082 165.98V165.98' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M365.09 165.98H369.074' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M425.75 150.211V150.211' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M423.758 150.211H427.742' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip7)' d='M425.75 150.211V150.211' fill='#850a85'/>
|
||||
<path clip-path='url(#clip7)' d='M423.758 150.211H427.742' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(0 -1 1 0 -115.838 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -57.169 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 1.5 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 60.169 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 118.838 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 177.507 269.769)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -110.608 183.001)'>
|
||||
<use x='114.487' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -51.938 280.841)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-56' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 6.731 254.133)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 65.4 263.058)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 124.069 301.711)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 182.738 299.43)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -105.377 246.416)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -46.708 271.245)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 11.961 266.078)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 70.63 249.302)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 129.299 300.101)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 187.968 288.156)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-55' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -100.147 249.167)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -41.478 260.978)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 17.191 223.466)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-54' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 75.86 276.077)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 134.529 298.021)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 193.198 302.651)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -94.916 271.312)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -36.247 265.474)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 22.422 250.375)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 81.091 258.696)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 139.76 259.233)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 198.429 211.387)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-56' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -89.686 242.188)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -31.017 256.415)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 27.652 253.194)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 86.321 268.762)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 144.99 277.083)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-56' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 203.659 289.767)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-55' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -84.455 248.765)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -25.786 267.756)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 32.883 267.689)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 91.552 266.078)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 150.221 280.64)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-56' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 208.89 292.921)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-54' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -79.225 271.379)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -20.556 260.106)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 38.113 269.366)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 96.782 275.741)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 155.451 276.48)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 214.12 307.617)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -73.994 266.279)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -15.325 262.253)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 43.344 262.589)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 102.013 230.914)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 160.682 274.265)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-57' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 219.351 258.495)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='208.035'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='208.035'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='208.035'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -148.675 311.091)'>
|
||||
<use x='114.487' xlink:href='#g1-82' y='208.035'/>
|
||||
<use x='120.457' xlink:href='#g1-101' y='208.035'/>
|
||||
<use x='124.553' xlink:href='#g1-108' y='208.035'/>
|
||||
<use x='126.753' xlink:href='#g1-97' y='208.035'/>
|
||||
<use x='131.181' xlink:href='#g1-116' y='208.035'/>
|
||||
<use x='134.509' xlink:href='#g1-105' y='208.035'/>
|
||||
<use x='136.709' xlink:href='#g1-118' y='208.035'/>
|
||||
<use x='140.957' xlink:href='#g1-101' y='208.035'/>
|
||||
<use x='148.124' xlink:href='#g1-114' y='208.035'/>
|
||||
<use x='151.272' xlink:href='#g1-115' y='208.035'/>
|
||||
<use x='154.805' xlink:href='#g1-115' y='208.035'/>
|
||||
<use x='161.409' xlink:href='#g3-40' y='208.035'/>
|
||||
<use x='164.702' xlink:href='#g3-108' y='208.035'/>
|
||||
<use x='166.722' xlink:href='#g3-111' y='208.035'/>
|
||||
<use x='170.721' xlink:href='#g3-119' y='208.035'/>
|
||||
<use x='176.27' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='180.034' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='185.749' xlink:href='#g3-105' y='208.035'/>
|
||||
<use x='187.769' xlink:href='#g3-115' y='208.035'/>
|
||||
<use x='193.838' xlink:href='#g3-98' y='208.035'/>
|
||||
<use x='198.446' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='202.209' xlink:href='#g3-116' y='208.035'/>
|
||||
<use x='205.267' xlink:href='#g3-116' y='208.035'/>
|
||||
<use x='208.325' xlink:href='#g3-101' y='208.035'/>
|
||||
<use x='212.089' xlink:href='#g3-114' y='208.035'/>
|
||||
<use x='214.981' xlink:href='#g3-41' y='208.035'/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 63 KiB |
1027
doc/bench-c5-18xlarge-2020-01-20-rss-b.svg
Normal file
1027
doc/bench-c5-18xlarge-2020-01-20-rss-b.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 81 KiB |
867
doc/bench-r5a-12xlarge-2020-01-16-a.svg
Normal file
867
doc/bench-r5a-12xlarge-2020-01-16-a.svg
Normal file
@ -0,0 +1,867 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- This file was generated by dvisvgm 2.4.2 -->
|
||||
<svg height='165.084pt' version='1.1' viewBox='52.938 54.996 381.624 165.084' width='381.624pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
|
||||
<defs>
|
||||
<clipPath id='clip5'>
|
||||
<path d='M82.148 203.937H434.164V78.691H82.148Z'/>
|
||||
</clipPath>
|
||||
<use id='g3-40' transform='scale(1.143)' xlink:href='#g0-40'/>
|
||||
<use id='g3-41' transform='scale(1.143)' xlink:href='#g0-41'/>
|
||||
<use id='g3-78' transform='scale(1.143)' xlink:href='#g0-78'/>
|
||||
<use id='g3-97' transform='scale(1.143)' xlink:href='#g0-97'/>
|
||||
<use id='g3-98' transform='scale(1.143)' xlink:href='#g0-98'/>
|
||||
<use id='g3-99' transform='scale(1.143)' xlink:href='#g0-99'/>
|
||||
<use id='g3-100' transform='scale(1.143)' xlink:href='#g0-100'/>
|
||||
<use id='g3-101' transform='scale(1.143)' xlink:href='#g0-101'/>
|
||||
<use id='g3-102' transform='scale(1.143)' xlink:href='#g0-102'/>
|
||||
<use id='g3-105' transform='scale(1.143)' xlink:href='#g0-105'/>
|
||||
<use id='g3-108' transform='scale(1.143)' xlink:href='#g0-108'/>
|
||||
<use id='g3-109' transform='scale(1.143)' xlink:href='#g0-109'/>
|
||||
<use id='g3-110' transform='scale(1.143)' xlink:href='#g0-110'/>
|
||||
<use id='g3-111' transform='scale(1.143)' xlink:href='#g0-111'/>
|
||||
<use id='g3-112' transform='scale(1.143)' xlink:href='#g0-112'/>
|
||||
<use id='g3-114' transform='scale(1.143)' xlink:href='#g0-114'/>
|
||||
<use id='g3-115' transform='scale(1.143)' xlink:href='#g0-115'/>
|
||||
<use id='g3-116' transform='scale(1.143)' xlink:href='#g0-116'/>
|
||||
<use id='g3-119' transform='scale(1.143)' xlink:href='#g0-119'/>
|
||||
<path d='M3.891 -2.914C4.806 -3.165 5.452 -3.811 5.452 -4.546C5.452 -5.469 4.411 -6.223 3.129 -6.223H0.87V0H1.704V-2.824H3.138L4.842 0H5.703L3.891 -2.914ZM1.704 -3.407V-5.694H3.022C4.062 -5.694 4.671 -5.192 4.671 -4.546C4.671 -3.963 4.125 -3.407 3.022 -3.407H1.704Z' id='g1-82'/>
|
||||
<path d='M3.694 -2.591C3.694 -3.479 3.04 -4.133 2.152 -4.133C1.569 -4.133 1.139 -3.981 0.708 -3.739L0.762 -3.102C1.21 -3.434 1.65 -3.569 2.143 -3.569C2.645 -3.569 2.95 -3.165 2.95 -2.582V-2.206C1.408 -2.17 0.395 -1.766 0.395 -1.04C0.395 -0.619 0.672 0.099 1.453 0.099C1.632 0.099 2.412 0.081 2.977 -0.341V0H3.694V-2.591ZM2.95 -1.255C2.95 -1.067 2.95 -0.843 2.627 -0.655C2.403 -0.52 2.107 -0.484 1.928 -0.484C1.47 -0.484 1.085 -0.699 1.085 -1.058C1.085 -1.695 2.833 -1.722 2.95 -1.722V-1.255Z' id='g1-97'/>
|
||||
<path d='M3.829 -1.964C3.829 -2.242 3.82 -2.923 3.47 -3.461C3.093 -4.026 2.52 -4.133 2.179 -4.133C1.139 -4.133 0.314 -3.174 0.314 -2.026C0.314 -0.843 1.193 0.099 2.313 0.099C2.744 0.099 3.264 -0.009 3.784 -0.341L3.73 -0.959C3.165 -0.556 2.636 -0.484 2.322 -0.484C1.578 -0.484 1.004 -1.139 0.977 -1.964H3.829ZM1.031 -2.493C1.175 -3.067 1.614 -3.551 2.179 -3.551C2.511 -3.551 3.12 -3.398 3.291 -2.493H1.031Z' id='g1-101'/>
|
||||
<path d='M1.524 -6.133H0.664V-5.272H1.524V-6.133ZM1.453 -3.981H0.735V0H1.453V-3.981Z' id='g1-105'/>
|
||||
<path d='M1.453 -6.223H0.735V0H1.453V-6.223Z' id='g1-108'/>
|
||||
<path d='M6.581 -2.663C6.581 -3.327 6.402 -4.08 5.317 -4.08C4.564 -4.08 4.142 -3.622 3.927 -3.344C3.865 -3.524 3.676 -4.08 2.762 -4.08C2.053 -4.08 1.623 -3.667 1.417 -3.398V-4.035H0.726V0H1.47V-2.188C1.47 -2.78 1.704 -3.497 2.385 -3.497C3.282 -3.497 3.282 -2.86 3.282 -2.6V0H4.026V-2.188C4.026 -2.78 4.259 -3.497 4.94 -3.497C5.837 -3.497 5.837 -2.86 5.837 -2.6V0H6.581V-2.663Z' id='g1-109'/>
|
||||
<path d='M1.623 -3.425H2.914V-3.981H1.623V-5.12H0.959V-3.981H0.17V-3.425H0.933V-1.13C0.933 -0.601 1.049 0.099 1.704 0.099C2.098 0.099 2.564 0.018 3.067 -0.233L2.914 -0.798C2.681 -0.619 2.367 -0.511 2.089 -0.511C1.739 -0.511 1.623 -0.825 1.623 -1.291V-3.425Z' id='g1-116'/>
|
||||
<path d='M4.116 -3.981H3.407L2.699 -2.161C2.52 -1.695 2.188 -0.825 2.143 -0.493H2.125C2.107 -0.646 2.08 -0.816 1.587 -2.107C1.318 -2.833 0.879 -3.927 0.861 -3.981H0.126L1.704 0H2.537L4.116 -3.981Z' id='g1-118'/>
|
||||
<use id='g2-46' transform='scale(0.714)' xlink:href='#g0-46'/>
|
||||
<use id='g2-48' transform='scale(0.714)' xlink:href='#g0-48'/>
|
||||
<use id='g2-49' transform='scale(0.714)' xlink:href='#g0-49'/>
|
||||
<use id='g2-50' transform='scale(0.714)' xlink:href='#g0-50'/>
|
||||
<use id='g2-51' transform='scale(0.714)' xlink:href='#g0-51'/>
|
||||
<use id='g2-52' transform='scale(0.714)' xlink:href='#g0-52'/>
|
||||
<use id='g2-53' transform='scale(0.714)' xlink:href='#g0-53'/>
|
||||
<use id='g2-54' transform='scale(0.714)' xlink:href='#g0-54'/>
|
||||
<use id='g2-55' transform='scale(0.714)' xlink:href='#g0-55'/>
|
||||
<use id='g2-56' transform='scale(0.714)' xlink:href='#g0-56'/>
|
||||
<use id='g2-57' transform='scale(0.714)' xlink:href='#g0-57'/>
|
||||
<use id='g2-120' transform='scale(0.714)' xlink:href='#g0-120'/>
|
||||
<path d='M1.445 -1.245C1.445 -1.41 1.305 -1.549 1.141 -1.549S0.837 -1.41 0.837 -1.245S0.976 -0.941 1.141 -0.941S1.445 -1.081 1.445 -1.245Z' id='g4-1'/>
|
||||
<path d='M2.127 -5.23C2.008 -5.23 1.995 -5.23 1.911 -5.154C1.032 -4.387 0.586 -3.145 0.586 -1.743C0.586 -0.425 0.983 0.844 1.904 1.653C1.995 1.743 2.008 1.743 2.127 1.743H2.462C2.441 1.73 1.764 1.151 1.444 0.063C1.276 -0.481 1.193 -1.053 1.193 -1.743C1.193 -4.156 2.322 -5.112 2.462 -5.23H2.127Z' id='g0-40'/>
|
||||
<path d='M0.746 1.743C0.865 1.743 0.879 1.743 0.962 1.667C1.841 0.9 2.287 -0.342 2.287 -1.743C2.287 -3.062 1.89 -4.331 0.969 -5.14C0.879 -5.23 0.865 -5.23 0.746 -5.23H0.411C0.432 -5.216 1.109 -4.638 1.43 -3.55C1.597 -3.006 1.681 -2.434 1.681 -1.743C1.681 0.669 0.551 1.625 0.411 1.743H0.746Z' id='g0-41'/>
|
||||
<path d='M1.339 -0.628H0.711V0H1.339V-0.628Z' id='g0-46'/>
|
||||
<path d='M3.403 -2.267C3.403 -2.601 3.403 -3.417 3.075 -3.989C2.72 -4.617 2.183 -4.721 1.848 -4.721C1.534 -4.721 0.99 -4.624 0.642 -4.024C0.307 -3.466 0.293 -2.706 0.293 -2.267C0.293 -1.75 0.321 -1.116 0.614 -0.586C0.921 -0.021 1.437 0.146 1.848 0.146C2.545 0.146 2.929 -0.258 3.138 -0.697C3.382 -1.193 3.403 -1.834 3.403 -2.267ZM1.848 -0.314C1.555 -0.314 1.22 -0.481 1.046 -0.983C0.907 -1.409 0.9 -1.848 0.9 -2.357C0.9 -2.999 0.9 -4.261 1.848 -4.261S2.797 -2.999 2.797 -2.357C2.797 -1.897 2.797 -1.374 2.629 -0.928C2.434 -0.425 2.078 -0.314 1.848 -0.314Z' id='g0-48'/>
|
||||
<path d='M2.239 -4.721H2.085C1.632 -4.303 1.06 -4.275 0.642 -4.261V-3.822C0.914 -3.829 1.262 -3.843 1.611 -3.982V-0.439H0.683V0H3.166V-0.439H2.239V-4.721Z' id='g0-49'/>
|
||||
<path d='M1.974 -0.537C1.89 -0.537 1.806 -0.53 1.723 -0.53H0.928L2.008 -1.485C2.134 -1.597 2.476 -1.855 2.608 -1.967C2.915 -2.246 3.327 -2.608 3.327 -3.215C3.327 -4.003 2.741 -4.721 1.743 -4.721C1.004 -4.721 0.544 -4.324 0.307 -3.612L0.635 -3.201C0.795 -3.787 1.039 -4.24 1.646 -4.24C2.232 -4.24 2.678 -3.829 2.678 -3.201C2.678 -2.622 2.336 -2.294 1.918 -1.897C1.778 -1.757 1.402 -1.444 1.255 -1.304C1.053 -1.123 0.572 -0.656 0.37 -0.481V0H3.327V-0.537H1.974Z' id='g0-50'/>
|
||||
<path d='M0.697 -3.578C0.983 -4.135 1.485 -4.289 1.82 -4.289C2.232 -4.289 2.538 -4.052 2.538 -3.654C2.538 -3.285 2.287 -2.831 1.757 -2.741C1.723 -2.734 1.695 -2.734 1.234 -2.699V-2.239H1.778C2.441 -2.239 2.685 -1.716 2.685 -1.276C2.685 -0.732 2.35 -0.314 1.806 -0.314C1.311 -0.314 0.746 -0.551 0.398 -0.997L0.307 -0.544C0.711 -0.091 1.276 0.146 1.82 0.146C2.734 0.146 3.389 -0.537 3.389 -1.269C3.389 -1.841 2.929 -2.301 2.378 -2.462C2.908 -2.734 3.18 -3.201 3.18 -3.654C3.18 -4.247 2.573 -4.721 1.827 -4.721C1.213 -4.721 0.704 -4.4 0.411 -3.982L0.697 -3.578Z' id='g0-51'/>
|
||||
<path d='M2.762 -1.165H3.487V-1.625H2.762V-4.575H2.071L0.209 -1.625V-1.165H2.162V0H2.762V-1.165ZM0.802 -1.625C1.011 -1.953 2.211 -3.815 2.211 -4.233V-1.625H0.802Z' id='g0-52'/>
|
||||
<path d='M1.144 -4.094H3.075V-4.575H0.586V-1.967H1.095C1.262 -2.343 1.59 -2.511 1.904 -2.511C2.19 -2.511 2.622 -2.315 2.622 -1.43C2.622 -0.516 2.043 -0.314 1.688 -0.314C1.227 -0.314 0.781 -0.558 0.544 -0.955L0.279 -0.537C0.621 -0.112 1.137 0.146 1.688 0.146C2.608 0.146 3.327 -0.565 3.327 -1.416C3.327 -2.28 2.685 -2.971 1.918 -2.971C1.618 -2.971 1.353 -2.866 1.144 -2.692V-4.094Z' id='g0-53'/>
|
||||
<path d='M3.062 -4.582C2.685 -4.721 2.42 -4.721 2.287 -4.721C1.227 -4.721 0.307 -3.724 0.307 -2.253C0.307 -0.363 1.158 0.146 1.862 0.146C2.427 0.146 2.72 -0.119 2.936 -0.342C3.382 -0.816 3.389 -1.311 3.389 -1.555C3.389 -2.469 2.894 -3.229 2.218 -3.229C1.534 -3.229 1.165 -2.873 0.962 -2.671C1.053 -3.626 1.541 -4.289 2.294 -4.289C2.434 -4.289 2.713 -4.275 3.062 -4.142V-4.582ZM0.969 -1.534C0.969 -1.576 0.969 -1.681 0.976 -1.716C0.976 -2.19 1.276 -2.769 1.897 -2.769C2.748 -2.769 2.748 -1.792 2.748 -1.555C2.748 -1.29 2.748 -0.997 2.559 -0.704C2.392 -0.453 2.183 -0.314 1.862 -0.314C1.123 -0.314 1.004 -1.227 0.969 -1.534Z' id='g0-54'/>
|
||||
<path d='M1.723 -4.038C1.806 -4.038 1.89 -4.045 1.974 -4.045H2.852C1.792 -3.006 1.116 -1.548 1.116 0.07H1.771C1.771 -1.967 2.762 -3.431 3.389 -4.087V-4.575H0.307V-4.038H1.723Z' id='g0-55'/>
|
||||
<path d='M2.385 -2.469C2.845 -2.615 3.285 -2.985 3.285 -3.501C3.285 -4.135 2.678 -4.721 1.848 -4.721S0.411 -4.135 0.411 -3.501C0.411 -2.978 0.865 -2.608 1.311 -2.469C0.697 -2.28 0.307 -1.806 0.307 -1.269C0.307 -0.523 0.969 0.146 1.848 0.146S3.389 -0.523 3.389 -1.269C3.389 -1.806 2.992 -2.28 2.385 -2.469ZM1.848 -2.699C1.353 -2.699 0.948 -2.985 0.948 -3.494C0.948 -3.94 1.262 -4.289 1.848 -4.289C2.427 -4.289 2.748 -3.94 2.748 -3.494C2.748 -2.999 2.357 -2.699 1.848 -2.699ZM1.848 -0.314C1.367 -0.314 0.941 -0.621 0.941 -1.276C0.941 -1.904 1.346 -2.239 1.848 -2.239S2.755 -1.897 2.755 -1.276C2.755 -0.621 2.322 -0.314 1.848 -0.314Z' id='g0-56'/>
|
||||
<path d='M0.537 -0.174C0.879 0.077 1.193 0.146 1.52 0.146C2.497 0.146 3.389 -0.837 3.389 -2.336C3.389 -4.24 2.545 -4.721 1.876 -4.721C1.255 -4.721 0.969 -4.428 0.767 -4.226C0.321 -3.773 0.307 -3.292 0.307 -3.02C0.307 -2.12 0.795 -1.346 1.478 -1.346C2.267 -1.346 2.699 -1.869 2.734 -1.911C2.636 -0.802 2.092 -0.314 1.52 -0.314C1.158 -0.314 0.934 -0.446 0.774 -0.579L0.537 -0.174ZM2.713 -3.027C2.72 -2.985 2.72 -2.915 2.72 -2.873C2.72 -2.357 2.406 -1.806 1.799 -1.806C1.534 -1.806 1.325 -1.883 1.144 -2.169C0.962 -2.441 0.948 -2.706 0.948 -3.02C0.948 -3.292 0.948 -3.605 1.165 -3.912C1.311 -4.122 1.52 -4.289 1.869 -4.289C2.545 -4.289 2.692 -3.473 2.713 -3.027Z' id='g0-57'/>
|
||||
<path d='M1.646 -4.84H0.697V0H1.283V-4.289H1.29L3.578 0H4.526V-4.84H3.94V-0.551H3.933L1.646 -4.84Z' id='g0-78'/>
|
||||
<path d='M2.971 -2.008C2.971 -2.72 2.427 -3.201 1.736 -3.201C1.297 -3.201 0.962 -3.11 0.572 -2.901L0.614 -2.392C0.844 -2.545 1.186 -2.755 1.736 -2.755C2.043 -2.755 2.364 -2.525 2.364 -2.001V-1.723C1.332 -1.688 0.314 -1.471 0.314 -0.823C0.314 -0.474 0.551 0.07 1.165 0.07C1.465 0.07 2.015 0.007 2.385 -0.265V0H2.971V-2.008ZM2.364 -0.99C2.364 -0.851 2.364 -0.669 2.12 -0.523C1.897 -0.398 1.625 -0.391 1.548 -0.391C1.165 -0.391 0.872 -0.565 0.872 -0.83C0.872 -1.276 2.05 -1.318 2.364 -1.332V-0.99Z' id='g0-97'/>
|
||||
<path d='M1.179 -4.84H0.593V0H1.2V-0.328C1.353 -0.195 1.688 0.07 2.197 0.07C2.957 0.07 3.571 -0.642 3.571 -1.555C3.571 -2.399 3.089 -3.166 2.392 -3.166C1.953 -3.166 1.527 -3.027 1.179 -2.769V-4.84ZM1.2 -2.197C1.2 -2.308 1.2 -2.392 1.444 -2.552C1.548 -2.615 1.736 -2.706 1.974 -2.706C2.441 -2.706 2.964 -2.392 2.964 -1.555C2.964 -0.704 2.385 -0.391 1.897 -0.391C1.639 -0.391 1.395 -0.509 1.2 -0.823V-2.197Z' id='g0-98'/>
|
||||
<path d='M3.034 -0.76C2.685 -0.537 2.308 -0.411 1.876 -0.411C1.234 -0.411 0.858 -0.928 0.858 -1.555C0.858 -2.092 1.137 -2.72 1.897 -2.72C2.371 -2.72 2.594 -2.622 2.95 -2.399L3.041 -2.901C2.622 -3.11 2.441 -3.201 1.897 -3.201C0.851 -3.201 0.251 -2.357 0.251 -1.548C0.251 -0.697 0.921 0.07 1.869 0.07C2.357 0.07 2.776 -0.077 3.075 -0.251L3.034 -0.76Z' id='g0-99'/>
|
||||
<path d='M3.229 -4.84H2.643V-2.797C2.197 -3.124 1.743 -3.166 1.541 -3.166C0.809 -3.166 0.251 -2.434 0.251 -1.548S0.802 0.07 1.52 0.07C1.953 0.07 2.357 -0.126 2.622 -0.363V0H3.229V-4.84ZM2.622 -0.865C2.448 -0.579 2.183 -0.391 1.848 -0.391C1.36 -0.391 0.858 -0.732 0.858 -1.541C0.858 -2.413 1.451 -2.706 1.925 -2.706C2.204 -2.706 2.441 -2.587 2.622 -2.35V-0.865Z' id='g0-100'/>
|
||||
<path d='M2.999 -0.76C2.608 -0.481 2.169 -0.391 1.869 -0.391C1.262 -0.391 0.802 -0.886 0.781 -1.527H3.068C3.068 -1.848 3.034 -2.315 2.762 -2.713C2.511 -3.068 2.092 -3.201 1.75 -3.201C0.9 -3.201 0.244 -2.455 0.244 -1.569C0.244 -0.676 0.941 0.07 1.862 0.07C2.267 0.07 2.685 -0.049 3.041 -0.265L2.999 -0.76ZM0.83 -1.946C0.99 -2.504 1.402 -2.741 1.75 -2.741C2.057 -2.741 2.511 -2.594 2.643 -1.946H0.83Z' id='g0-101'/>
|
||||
<path d='M1.325 -2.657H2.12V-3.096H1.304V-3.898C1.304 -4.38 1.743 -4.449 1.974 -4.449C2.12 -4.449 2.308 -4.428 2.566 -4.331V-4.84C2.385 -4.882 2.169 -4.91 1.981 -4.91C1.262 -4.91 0.739 -4.394 0.739 -3.703V-3.096H0.202V-2.657H0.739V0H1.325V-2.657Z' id='g0-102'/>
|
||||
<path d='M1.227 -4.784H0.523V-4.08H1.227V-4.784ZM1.172 -3.096H0.586V0H1.172V-3.096Z' id='g0-105'/>
|
||||
<path d='M1.172 -4.84H0.586V0H1.172V-4.84Z' id='g0-108'/>
|
||||
<path d='M5.3 -2.064C5.3 -2.608 5.14 -3.166 4.282 -3.166C3.696 -3.166 3.333 -2.824 3.166 -2.601C3.096 -2.79 2.922 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-1.695C3.243 -2.155 3.438 -2.706 3.975 -2.706C4.693 -2.706 4.693 -2.218 4.693 -2.015V0H5.3V-2.064Z' id='g0-109'/>
|
||||
<path d='M3.243 -2.064C3.243 -2.608 3.082 -3.166 2.225 -3.166C1.827 -3.166 1.444 -3.006 1.137 -2.636V-3.145H0.579V0H1.186V-1.695C1.186 -2.155 1.381 -2.706 1.918 -2.706C2.636 -2.706 2.636 -2.218 2.636 -2.015V0H3.243V-2.064Z' id='g0-110'/>
|
||||
<path d='M3.487 -1.527C3.487 -2.448 2.755 -3.201 1.848 -3.201S0.209 -2.441 0.209 -1.527C0.209 -0.642 0.948 0.07 1.848 0.07C2.755 0.07 3.487 -0.642 3.487 -1.527ZM1.848 -0.411C1.297 -0.411 0.816 -0.816 0.816 -1.604S1.332 -2.741 1.848 -2.741C2.371 -2.741 2.88 -2.378 2.88 -1.604C2.88 -0.809 2.385 -0.411 1.848 -0.411Z' id='g0-111'/>
|
||||
<path d='M1.2 -0.328C1.569 0.007 1.967 0.07 2.204 0.07C2.943 0.07 3.571 -0.635 3.571 -1.555C3.571 -2.392 3.11 -3.166 2.42 -3.166C2.106 -3.166 1.583 -3.075 1.179 -2.762V-3.096H0.593V1.353H1.2V-0.328ZM1.2 -2.315C1.36 -2.511 1.632 -2.685 1.967 -2.685C2.525 -2.685 2.964 -2.169 2.964 -1.555C2.964 -0.865 2.441 -0.391 1.897 -0.391C1.792 -0.391 1.618 -0.404 1.437 -0.551C1.227 -0.711 1.2 -0.816 1.2 -0.948V-2.315Z' id='g0-112'/>
|
||||
<path d='M1.179 -1.485C1.179 -2.239 1.806 -2.643 2.42 -2.65V-3.166C1.834 -3.159 1.409 -2.873 1.13 -2.504V-3.145H0.593V0H1.179V-1.485Z' id='g0-114'/>
|
||||
<path d='M2.545 -2.985C2.071 -3.18 1.723 -3.201 1.471 -3.201C1.297 -3.201 0.244 -3.201 0.244 -2.273C0.244 -1.946 0.425 -1.764 0.516 -1.681C0.76 -1.437 1.053 -1.381 1.423 -1.311C1.75 -1.248 2.127 -1.179 2.127 -0.844C2.127 -0.404 1.548 -0.404 1.451 -0.404C1.004 -0.404 0.586 -0.565 0.307 -0.76L0.209 -0.237C0.446 -0.119 0.872 0.07 1.451 0.07C1.764 0.07 2.071 0.021 2.329 -0.167C2.587 -0.363 2.671 -0.669 2.671 -0.907C2.671 -1.032 2.657 -1.304 2.364 -1.569C2.106 -1.799 1.855 -1.848 1.52 -1.911C1.109 -1.988 0.788 -2.05 0.788 -2.357C0.788 -2.755 1.297 -2.755 1.402 -2.755C1.799 -2.755 2.106 -2.671 2.455 -2.49L2.545 -2.985Z' id='g0-115'/>
|
||||
<path d='M1.311 -2.657H2.343V-3.096H1.311V-3.982H0.774V-3.096H0.139V-2.657H0.753V-0.893C0.753 -0.425 0.872 0.07 1.374 0.07S2.26 -0.091 2.469 -0.188L2.35 -0.635C2.12 -0.467 1.876 -0.411 1.681 -0.411C1.388 -0.411 1.311 -0.697 1.311 -1.018V-2.657Z' id='g0-116'/>
|
||||
<path d='M4.951 -3.096H4.407C4.345 -2.901 3.954 -1.723 3.738 -0.997C3.682 -0.795 3.612 -0.572 3.592 -0.411H3.585C3.543 -0.697 3.299 -1.451 3.285 -1.499L2.769 -3.096H2.239C2.036 -2.497 1.513 -0.934 1.458 -0.425H1.451C1.395 -0.921 0.879 -2.462 0.767 -2.797C0.711 -2.964 0.711 -2.978 0.676 -3.096H0.105L1.123 0H1.709C1.716 -0.028 1.904 -0.579 2.148 -1.353C2.253 -1.695 2.462 -2.364 2.497 -2.671L2.504 -2.678C2.518 -2.532 2.559 -2.378 2.608 -2.204S2.706 -1.841 2.755 -1.681L3.292 0H3.933L4.951 -3.096Z' id='g0-119'/>
|
||||
<path d='M1.932 -1.597L3.285 -3.096H2.671L1.681 -1.953L0.669 -3.096H0.042L1.437 -1.597L0 0H0.621L1.681 -1.311L2.783 0H3.41L1.932 -1.597Z' id='g0-120'/>
|
||||
</defs>
|
||||
<g id='page5'>
|
||||
<path d='M140.82 212.793V203.937M199.488 212.793V203.937M258.156 212.793V203.937M316.824 212.793V203.937M375.496 212.793V203.937M140.82 69.836V78.691M199.488 69.836V78.691M258.156 69.836V78.691M316.824 69.836V78.691M375.496 69.836V78.691' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M111.484 208.191V203.937M170.152 208.191V203.937M228.824 208.191V203.937M287.492 208.191V203.937M346.16 208.191V203.937M404.828 208.191V203.937M111.484 74.441V78.691M170.152 74.441V78.691M228.824 74.441V78.691M287.492 74.441V78.691M346.16 74.441V78.691M404.828 74.441V78.691' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 203.937H86.402M82.148 172.625H86.402M82.148 141.316H86.402M82.148 110.004H86.402M82.148 78.691H86.402M434.164 203.937H429.91M434.164 172.625H429.91M434.164 141.316H429.91M434.164 110.004H429.91M434.164 78.691H429.91' fill='none' stroke='#808080' stroke-miterlimit='10' stroke-width='0.199'/>
|
||||
<path d='M82.148 203.937V78.691H434.164V203.937H82.148Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(1 0 0 1 -11.54 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-99' y='183.381'/>
|
||||
<use x='118.25' xlink:href='#g3-102' y='183.381'/>
|
||||
<use x='120.838' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='123.73' xlink:href='#g3-97' y='183.381'/>
|
||||
<use x='127.798' xlink:href='#g3-99' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 45.565 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='183.381'/>
|
||||
<use x='116.507' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='120.271' xlink:href='#g3-97' y='183.381'/>
|
||||
<use x='124.339' xlink:href='#g3-110' y='183.381'/>
|
||||
<use x='128.711' xlink:href='#g3-78' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 106.188 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='117.379' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='121.142' xlink:href='#g3-100' y='183.381'/>
|
||||
<use x='125.515' xlink:href='#g3-105' y='183.381'/>
|
||||
<use x='127.535' xlink:href='#g3-115' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 159.716 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-108' y='183.381'/>
|
||||
<use x='116.507' xlink:href='#g3-97' y='183.381'/>
|
||||
<use x='120.34' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='123.232' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='126.478' xlink:href='#g3-111' y='183.381'/>
|
||||
<use x='130.712' xlink:href='#g3-110' y='183.381'/>
|
||||
<use x='135.085' xlink:href='#g3-78' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 215.596 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-109' y='183.381'/>
|
||||
<use x='121.211' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='124.458' xlink:href='#g3-116' y='183.381'/>
|
||||
<use x='127.516' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='130.408' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='134.171' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='137.418' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='140.664' xlink:href='#g3-78' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 277.158 34.954)'>
|
||||
<use x='114.487' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='117.379' xlink:href='#g3-112' y='183.381'/>
|
||||
<use x='121.751' xlink:href='#g3-116' y='183.381'/>
|
||||
<use x='124.809' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='128.573' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='131.819' xlink:href='#g3-116' y='183.381'/>
|
||||
<use x='134.877' xlink:href='#g3-78' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -40.942 22.192)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -9.12)'>
|
||||
<use x='114.487' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -40.431)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -71.743)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(1 0 0 1 -45.059 -103.054)'>
|
||||
<use x='114.487' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<path clip-path='url(#clip5)' d='M82.148 141.316H434.164' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M88.945 203.937H92.18V141.316H88.945ZM147.613 203.937H150.852V141.316H147.613ZM206.281 203.937H209.52V141.316H206.281ZM264.949 203.937H268.188V141.316H264.949ZM323.621 203.937H326.859V141.316H323.621ZM382.289 203.937H385.527V141.316H382.289Z' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M88.945 203.937H92.18V141.316H88.945ZM147.613 203.937H150.852V141.316H147.613ZM206.281 203.937H209.52V141.316H206.281ZM264.949 203.937H268.188V141.316H264.949ZM323.621 203.937H326.859V141.316H323.621ZM382.289 203.937H385.527V141.316H382.289Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M90.563 141.316V141.129' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M90.563 141.316V141.129' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M88.57 141.129H92.555' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M90.563 141.316V141.504' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M90.563 141.316V141.504' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M92.555 141.504H88.57' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M149.231 141.316V140.937' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M149.231 141.316V140.937' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M147.238 140.937H151.223' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M149.231 141.316V141.691' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M149.231 141.316V141.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M151.223 141.692H147.238' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M207.902 141.316V139.562' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M207.902 141.316V139.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M205.906 139.563H209.894' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M207.902 141.316V143.07' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M207.902 141.316V143.07' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M209.895 143.071H205.91' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M266.57 141.316V140.25' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M266.57 141.316V140.25' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M264.578 140.25H268.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M266.57 141.316V142.379' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M266.57 141.316V142.379' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M268.562 142.379H264.578' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M325.238 141.316V139.312' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M325.238 141.316V139.312' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M323.246 139.312H327.23' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M325.238 141.316V143.32' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M325.238 141.316V143.32' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M327.231 143.32H323.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M383.906 141.316V139.875' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M383.906 141.316V139.875' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M381.914 139.875H385.898' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M383.906 141.316V142.754' fill='#993333'/>
|
||||
<path clip-path='url(#clip5)' d='M383.906 141.316V142.754' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M385.902 142.753H381.914' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M94.176 203.937H97.41V140.875H94.176ZM152.844 203.937H156.082V135.617H152.844ZM211.512 203.937H214.75V136.805H211.512ZM270.18 203.937H273.418V78.691H270.18ZM328.852 203.937H332.09V139.625H328.852ZM387.52 203.937H390.758V105.746H387.52Z' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M94.176 203.937H97.41V140.875H94.176ZM152.844 203.937H156.082V135.617H152.844ZM211.512 203.937H214.75V136.805H211.512ZM270.18 203.937H273.418V78.691H270.18ZM328.852 203.937H332.09V139.625H328.852ZM387.52 203.937H390.758V105.746H387.52Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M95.793 140.875V140.625' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M95.793 140.875V140.625' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M93.801 140.625H97.785' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M95.793 140.875V141.129' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M95.793 140.875V141.129' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M97.785 141.129H93.801' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M154.461 135.617V135.242' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M154.461 135.617V135.242' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M152.469 135.242H156.454' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M154.461 135.617V135.992' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M154.461 135.617V135.992' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M156.453 135.992H152.468' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M213.133 136.805V135.68' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M213.133 136.805V135.68' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M211.137 135.68H215.125' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M213.133 136.805V137.934' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M213.133 136.805V137.934' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M215.125 137.934H211.14' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M271.801 78.691V78.691' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M269.809 78.691H273.793' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M271.801 78.691V78.691' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M269.809 78.691H273.793' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M330.469 139.625V139.312' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M330.469 139.625V139.312' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M328.477 139.312H332.461' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M330.469 139.625V139.937' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M330.469 139.625V139.937' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M332.461 139.937H328.476' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M389.137 105.746V99.609' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M389.137 105.746V99.609' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M387.145 99.609H391.129' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M389.137 105.746V111.883' fill='#8080bf'/>
|
||||
<path clip-path='url(#clip5)' d='M389.137 105.746V111.883' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M391.132 111.883H387.144' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M99.406 203.937H102.641V139.437H99.406ZM158.074 203.937H161.313V140.437H158.074ZM216.742 203.937H219.981V132.922H216.742ZM275.41 203.937H278.649V78.691H275.41ZM334.082 203.937H337.32V106.996H334.082ZM392.75 203.937H395.988V78.691H392.75Z' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M99.406 203.937H102.641V139.437H99.406ZM158.074 203.937H161.313V140.437H158.074ZM216.742 203.937H219.981V132.922H216.742ZM275.41 203.937H278.649V78.691H275.41ZM334.082 203.937H337.32V106.996H334.082ZM392.75 203.937H395.988V78.691H392.75Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M101.024 139.437V139.25' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M101.024 139.437V139.25' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M99.031 139.25H103.016' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M101.024 139.437V139.625' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M101.024 139.437V139.625' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M103.016 139.625H99.031' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M159.691 140.437V140.062' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M159.691 140.437V140.062' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M157.699 140.063H161.684' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M159.691 140.437V140.812' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M159.691 140.437V140.812' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M161.684 140.812H157.699' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M218.363 132.922V131.547' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M218.363 132.922V131.547' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M216.367 131.547H220.355' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M218.363 132.922V134.301' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M218.363 132.922V134.301' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M220.356 134.3H216.371' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M277.031 78.691V78.691' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M275.039 78.691H279.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M277.031 78.691V78.691' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M275.039 78.691H279.023' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M335.699 106.996V105.621' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M335.699 106.996V105.621' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M333.707 105.621H337.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M335.699 106.996V108.375' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M335.699 106.996V108.375' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M337.692 108.375H333.707' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M394.367 78.691V78.691' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M392.375 78.691H396.359' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M394.367 78.691V78.691' fill='#ffb733'/>
|
||||
<path clip-path='url(#clip5)' d='M392.375 78.691H396.359' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M104.637 203.937H107.871V124.344H104.637ZM163.305 203.937H166.543V135.742H163.305ZM221.973 203.937H225.211V105.996H221.973ZM280.641 203.937H283.879V98.168H280.641ZM339.313 203.937H342.551V122.715H339.313ZM397.981 203.937H401.219V120.336H397.981Z' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M104.637 203.937H107.871V124.344H104.637ZM163.305 203.937H166.543V135.742H163.305ZM221.973 203.937H225.211V105.996H221.973ZM280.641 203.937H283.879V98.168H280.641ZM339.313 203.937H342.551V122.715H339.313ZM397.981 203.937H401.219V120.336H397.981Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M106.254 124.344V124.031' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M106.254 124.344V124.031' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M104.261 124.031H108.246' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M106.254 124.344V124.656' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M106.254 124.344V124.656' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M108.246 124.656H104.261' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M164.922 135.742V135.555' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M164.922 135.742V135.555' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M162.929 135.555H166.914' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M164.922 135.742V135.93' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M164.922 135.742V135.93' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M166.914 135.93H162.929' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M223.594 105.996V104.805' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M223.594 105.996V104.805' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M221.597 104.805H225.585' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M223.594 105.996V107.187' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M223.594 105.996V107.187' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M225.586 107.188H221.601' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M282.262 98.168V96.289' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M282.262 98.168V96.289' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M280.269 96.289H284.253' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M282.262 98.168V100.047' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M282.262 98.168V100.047' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M284.254 100.047H280.269' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M340.93 122.715V121.527' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M340.93 122.715V121.527' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M338.937 121.527H342.921' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M340.93 122.715V123.906' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M340.93 122.715V123.906' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M342.922 123.906H338.937' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M399.598 120.336V114.137' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M399.598 120.336V114.137' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M397.605 114.137H401.589' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M399.598 120.336V126.535' fill='#bf80bf'/>
|
||||
<path clip-path='url(#clip5)' d='M399.598 120.336V126.535' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M401.593 126.535H397.605' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M109.867 203.937H113.102V140.687H109.867ZM168.535 203.937H171.774V141.316H168.535ZM227.203 203.937H230.442V140.625H227.203ZM285.871 203.937H289.109V136.555H285.871ZM344.543 203.937H347.781V115.453H344.543ZM403.211 203.937H406.449V135.242H403.211Z' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M109.867 203.937H113.102V140.687H109.867ZM168.535 203.937H171.774V141.316H168.535ZM227.203 203.937H230.442V140.625H227.203ZM285.871 203.937H289.109V136.555H285.871ZM344.543 203.937H347.781V115.453H344.543ZM403.211 203.937H406.449V135.242H403.211Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M111.484 140.687V140.562' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M111.484 140.687V140.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M109.492 140.563H113.477' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M111.484 140.687V140.812' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M111.484 140.687V140.812' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M113.477 140.812H109.492' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M170.152 141.316V140.937' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M170.152 141.316V140.937' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M168.16 140.937H172.145' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M170.152 141.316V141.691' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M170.152 141.316V141.691' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M172.145 141.692H168.16' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M228.824 140.625V139.25' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M228.824 140.625V139.25' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M226.828 139.25H230.816' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M228.824 140.625V142.004' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M228.824 140.625V142.004' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M230.817 142.004H226.832' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M287.492 136.555V134.801' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M287.492 136.555V134.801' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M285.5 134.8H289.484' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M287.492 136.555V138.309' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M287.492 136.555V138.309' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M289.485 138.308H285.5' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M346.16 115.453V114.074' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M346.16 115.453V114.074' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M344.168 114.074H348.152' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M346.16 115.453V116.828' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M346.16 115.453V116.828' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M348.153 116.829H344.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M404.828 135.242V128.539' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M404.828 135.242V128.539' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M402.836 128.539H406.82' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M404.828 135.242V141.941' fill='#dfbf9f'/>
|
||||
<path clip-path='url(#clip5)' d='M404.828 135.242V141.941' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M406.824 141.941H402.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M115.098 203.937H118.332V136.055H115.098ZM173.766 203.937H177.004V128.539H173.766ZM232.434 203.937H235.672V116.016H232.434ZM291.102 203.937H294.34V78.691H291.102ZM349.774 203.937H353.012V78.691H349.774ZM408.442 203.937H411.68V78.691H408.442Z' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M115.098 203.937H118.332V136.055H115.098ZM173.766 203.937H177.004V128.539H173.766ZM232.434 203.937H235.672V116.016H232.434ZM291.102 203.937H294.34V78.691H291.102ZM349.774 203.937H353.012V78.691H349.774ZM408.442 203.937H411.68V78.691H408.442Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M116.715 136.055V135.93' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M116.715 136.055V135.93' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M114.722 135.93H118.707' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M116.715 136.055V136.18' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M116.715 136.055V136.18' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M118.707 136.18H114.722' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M175.383 128.539V126.723' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M175.383 128.539V126.723' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M173.39 126.723H177.375' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M175.383 128.539V130.355' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M175.383 128.539V130.355' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M177.375 130.355H173.39' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M234.055 116.016V114.449' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M234.055 116.016V114.449' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M232.058 114.449H236.046' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M234.055 116.016V117.582' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M234.055 116.016V117.582' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M236.047 117.582H232.062' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M292.723 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M290.73 78.691H294.714' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M292.723 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M290.73 78.691H294.714' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M351.391 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M349.398 78.691H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M351.391 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M349.398 78.691H353.382' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M410.059 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M408.066 78.691H412.05' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M410.059 78.691V78.691' fill='#80bf80'/>
|
||||
<path clip-path='url(#clip5)' d='M408.066 78.691H412.05' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M120.328 203.937H123.563V137.621H120.328ZM178.996 203.937H182.234V197.676H178.996ZM237.664 203.937H240.902V136.43H237.664ZM296.332 203.937H299.57V116.953H296.332ZM355.004 203.937H358.238V197.676H355.004ZM413.672 203.937H416.91V78.691H413.672Z' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M120.328 203.937H123.563V137.621H120.328ZM178.996 203.937H182.234V197.676H178.996ZM237.664 203.937H240.902V136.43H237.664ZM296.332 203.937H299.57V116.953H296.332ZM355.004 203.937H358.238V197.676H355.004ZM413.672 203.937H416.91V78.691H413.672Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M121.945 137.621V137.371' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M121.945 137.621V137.371' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M119.953 137.371H123.938' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M121.945 137.621V137.871' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M121.945 137.621V137.871' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M123.938 137.871H119.953' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M180.613 197.676V197.676' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M178.621 197.676H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M180.613 197.676V197.676' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M178.621 197.676H182.606' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M239.285 136.43V134.988' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M239.285 136.43V134.988' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M237.289 134.988H241.274' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M239.285 136.43V137.871' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M239.285 136.43V137.871' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M241.278 137.871H237.293' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M297.953 116.953V115.391' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M297.953 116.953V115.391' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M295.961 115.39H299.945' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M297.953 116.953V118.519' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M297.953 116.953V118.519' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M299.946 118.519H295.961' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M356.621 197.676V197.676' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M354.629 197.676H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M356.621 197.676V197.676' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M354.629 197.676H358.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M415.289 78.691V78.691' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M413.297 78.691H417.281' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M415.289 78.691V78.691' fill='#bfbf80'/>
|
||||
<path clip-path='url(#clip5)' d='M413.297 78.691H417.281' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M125.559 203.937H128.793V138.121H125.559ZM184.227 203.937H187.465V132.047H184.227ZM242.895 203.937H246.133V134.426H242.895ZM301.563 203.937H304.801V78.691H301.563ZM360.234 203.937H363.469V78.691H360.234ZM418.902 203.937H422.141V109.254H418.902Z' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M125.559 203.937H128.793V138.121H125.559ZM184.227 203.937H187.465V132.047H184.227ZM242.895 203.937H246.133V134.426H242.895ZM301.563 203.937H304.801V78.691H301.563ZM360.234 203.937H363.469V78.691H360.234ZM418.902 203.937H422.141V109.254H418.902Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M127.176 138.121V137.934' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M127.176 138.121V137.934' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M125.183 137.934H129.168' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M127.176 138.121V138.309' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M127.176 138.121V138.309' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M129.168 138.308H125.183' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M185.844 132.047V131.672' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M185.844 132.047V131.672' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M183.851 131.672H187.836' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M185.844 132.047V132.422' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M185.844 132.047V132.422' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M187.836 132.422H183.851' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M244.516 134.426V133.488' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M244.516 134.426V133.488' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M242.519 133.488H246.504' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M244.516 134.426V135.367' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M244.516 134.426V135.367' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M246.508 135.367H242.523' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M303.184 78.691V78.691' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M301.191 78.691H305.175' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M303.184 78.691V78.691' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M301.191 78.691H305.175' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M361.852 78.691V78.691' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M359.859 78.691H363.843' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M361.852 78.691V78.691' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M359.859 78.691H363.843' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M420.52 109.254V107.25' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M420.52 109.254V107.25' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M418.527 107.25H422.511' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M420.52 109.254V111.258' fill='#339999'/>
|
||||
<path clip-path='url(#clip5)' d='M420.52 109.254V111.258' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M422.512 111.258H418.527' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M130.789 203.937H134.024V139.187H130.789ZM189.457 203.937H192.695V139.312H189.457ZM248.125 203.937H251.363V140.062H248.125ZM306.793 203.937H310.031V126.035H306.793ZM365.465 203.937H368.699V103.176H365.465ZM424.133 203.937H427.371V113.762H424.133Z' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M130.789 203.937H134.024V139.187H130.789ZM189.457 203.937H192.695V139.312H189.457ZM248.125 203.937H251.363V140.062H248.125ZM306.793 203.937H310.031V126.035H306.793ZM365.465 203.937H368.699V103.176H365.465ZM424.133 203.937H427.371V113.762H424.133Z' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M132.406 139.187V138.934' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M132.406 139.187V138.934' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M130.414 138.933H134.399' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M132.406 139.187V139.437' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M132.406 139.187V139.437' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M134.399 139.437H130.414' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M191.074 139.312V139.062' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M191.074 139.312V139.062' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M189.082 139.063H193.067' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M191.074 139.312V139.562' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M191.074 139.312V139.562' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M193.067 139.563H189.082' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M249.746 140.062V138.871' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M249.746 140.062V138.871' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M247.75 138.871H251.735' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M249.746 140.062V141.254' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M249.746 140.062V141.254' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M251.739 141.254H247.754' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M308.414 126.035V125.031' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M308.414 126.035V125.031' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M306.422 125.031H310.407' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M308.414 126.035V127.035' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M308.414 126.035V127.035' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M310.407 127.035H306.422' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M367.082 103.176V101.613' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M367.082 103.176V101.613' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M365.09 101.613H369.074' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M367.082 103.176V104.742' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M367.082 103.176V104.742' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M369.075 104.742H365.09' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M425.75 113.762V105.184' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M425.75 113.762V105.184' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M423.758 105.184H427.742' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M425.75 113.762V122.34' fill='#bf8080'/>
|
||||
<path clip-path='url(#clip5)' d='M425.75 113.762V122.34' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<path clip-path='url(#clip5)' d='M427.743 122.34H423.758' fill='none' stroke='#000000' stroke-miterlimit='10' stroke-width='0.399'/>
|
||||
<g transform='matrix(0 -1 1 0 -91.184 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -32.515 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 26.154 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 84.823 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 143.492 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 202.161 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -85.954 249.339)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -27.284 244.079)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 31.385 245.269)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 90.054 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-57' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 148.723 248.087)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 207.392 214.208)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -80.723 247.899)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -22.054 248.901)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 36.615 241.386)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 95.284 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 153.953 215.46)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 212.622 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-55' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-56' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -75.493 232.807)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-55' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -16.824 244.204)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 41.845 214.458)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 100.514 206.63)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-54' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 159.183 231.178)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 217.852 228.799)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -70.262 249.151)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -11.593 249.777)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 47.076 249.089)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 105.745 245.018)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 164.414 223.914)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 223.083 243.703)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -65.032 244.517)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -6.363 237.002)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 52.306 224.478)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-48' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 110.975 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 169.644 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 228.313 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-54' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -59.801 246.083)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-54' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -1.66 306.138)'>
|
||||
<use x='114.487' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 57.537 244.893)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-56' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 116.206 225.417)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-57' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 174.347 306.138)'>
|
||||
<use x='114.487' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 233.544 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-56' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -54.571 246.584)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 4.098 240.509)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-53' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 62.767 242.889)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 121.436 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-51' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 180.105 187.154)'>
|
||||
<use x='109.598' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='113.103' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='116.608' xlink:href='#g4-1' y='183.381'/>
|
||||
<use x='120.114' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='122.76' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='124.23' xlink:href='#g2-56' y='183.381'/>
|
||||
<use x='126.877' xlink:href='#g2-56' y='183.381'/>
|
||||
<use x='129.523' xlink:href='#g2-120' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 238.774 217.714)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-53' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -49.34 247.648)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 9.329 247.773)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-51' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 67.998 248.525)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-48' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-50' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 126.667 234.497)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-50' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 185.336 211.64)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-54' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-49' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 244.005 222.223)'>
|
||||
<use x='114.487' xlink:href='#g2-49' y='183.381'/>
|
||||
<use x='117.133' xlink:href='#g2-46' y='183.381'/>
|
||||
<use x='118.603' xlink:href='#g2-52' y='183.381'/>
|
||||
<use x='121.25' xlink:href='#g2-52' y='183.381'/>
|
||||
</g>
|
||||
<g transform='matrix(0 -1 1 0 -124.021 311.062)'>
|
||||
<use x='114.487' xlink:href='#g1-82' y='183.381'/>
|
||||
<use x='120.457' xlink:href='#g1-101' y='183.381'/>
|
||||
<use x='124.553' xlink:href='#g1-108' y='183.381'/>
|
||||
<use x='126.753' xlink:href='#g1-97' y='183.381'/>
|
||||
<use x='131.181' xlink:href='#g1-116' y='183.381'/>
|
||||
<use x='134.509' xlink:href='#g1-105' y='183.381'/>
|
||||
<use x='136.709' xlink:href='#g1-118' y='183.381'/>
|
||||
<use x='140.957' xlink:href='#g1-101' y='183.381'/>
|
||||
<use x='148.124' xlink:href='#g1-116' y='183.381'/>
|
||||
<use x='151.452' xlink:href='#g1-105' y='183.381'/>
|
||||
<use x='153.652' xlink:href='#g1-109' y='183.381'/>
|
||||
<use x='160.972' xlink:href='#g1-101' y='183.381'/>
|
||||
<use x='168.139' xlink:href='#g3-40' y='183.381'/>
|
||||
<use x='171.432' xlink:href='#g3-108' y='183.381'/>
|
||||
<use x='173.453' xlink:href='#g3-111' y='183.381'/>
|
||||
<use x='177.452' xlink:href='#g3-119' y='183.381'/>
|
||||
<use x='183' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='186.764' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='192.479' xlink:href='#g3-105' y='183.381'/>
|
||||
<use x='194.499' xlink:href='#g3-115' y='183.381'/>
|
||||
<use x='200.568' xlink:href='#g3-98' y='183.381'/>
|
||||
<use x='205.176' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='208.94' xlink:href='#g3-116' y='183.381'/>
|
||||
<use x='211.998' xlink:href='#g3-116' y='183.381'/>
|
||||
<use x='215.056' xlink:href='#g3-101' y='183.381'/>
|
||||
<use x='218.819' xlink:href='#g3-114' y='183.381'/>
|
||||
<use x='221.711' xlink:href='#g3-41' y='183.381'/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 75 KiB |
1156
doc/bench-r5a-12xlarge-2020-01-16-b.svg
Normal file
1156
doc/bench-r5a-12xlarge-2020-01-16-b.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 93 KiB |
@ -38,7 +38,7 @@ PROJECT_NAME = mi-malloc
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.0
|
||||
PROJECT_NUMBER = 1.4
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@ -1235,7 +1235,7 @@ HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css
|
||||
# files will be copied as-is; there are no commands or markers available.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_EXTRA_FILES =
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
|
@ -26,7 +26,7 @@ without code changes, for example, on Unix you can use it as:
|
||||
|
||||
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 less than 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
|
||||
@ -74,6 +74,8 @@ Further information:
|
||||
- \ref typed
|
||||
- \ref analysis
|
||||
- \ref options
|
||||
- \ref posix
|
||||
- \ref cpp
|
||||
|
||||
*/
|
||||
|
||||
@ -297,10 +299,17 @@ size_t mi_good_size(size_t size);
|
||||
void mi_collect(bool force);
|
||||
|
||||
/// Print the main statistics.
|
||||
/// @param out Output function. Use \a NULL for outputting to \a stderr.
|
||||
/// @param out Ignored, outputs to the registered output function or stderr by default.
|
||||
///
|
||||
/// Most detailed when using a debug build.
|
||||
void mi_stats_print(mi_output_fun* out);
|
||||
void mi_stats_print(void* out);
|
||||
|
||||
/// Print the main statistics.
|
||||
/// @param out An output function or \a NULL for the default.
|
||||
/// @param arg Optional argument passed to \a out (if not \a NULL)
|
||||
///
|
||||
/// Most detailed when using a debug build.
|
||||
void mi_stats_print(mi_output_fun* out, void* arg);
|
||||
|
||||
/// Reset statistics.
|
||||
void mi_stats_reset(void);
|
||||
@ -320,20 +329,23 @@ void mi_thread_init(void);
|
||||
void mi_thread_done(void);
|
||||
|
||||
/// Print out heap statistics for this thread.
|
||||
/// @param out Output function. Use \a NULL for outputting to \a stderr.
|
||||
/// @param out An output function or \a NULL for the default.
|
||||
/// @param arg Optional argument passed to \a out (if not \a NULL)
|
||||
///
|
||||
/// Most detailed when using a debug build.
|
||||
void mi_thread_stats_print(mi_output_fun* out);
|
||||
void mi_thread_stats_print_out(mi_output_fun* out, void* arg);
|
||||
|
||||
/// Type of deferred free functions.
|
||||
/// @param force If \a true all outstanding items should be freed.
|
||||
/// @param heartbeat A monotonically increasing count.
|
||||
/// @param arg Argument that was passed at registration to hold extra state.
|
||||
///
|
||||
/// @see mi_register_deferred_free
|
||||
typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
|
||||
typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
|
||||
|
||||
/// Register a deferred free function.
|
||||
/// @param deferred_free Address of a deferred free-ing function or \a NULL to unregister.
|
||||
/// @param arg Argument that will be passed on to the deferred free function.
|
||||
///
|
||||
/// Some runtime systems use deferred free-ing, for example when using
|
||||
/// reference counting to limit the worst case free time.
|
||||
@ -346,20 +358,46 @@ typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
|
||||
/// to be called deterministically after some number of allocations
|
||||
/// (regardless of freeing or available free memory).
|
||||
/// At most one \a deferred_free function can be active.
|
||||
void mi_register_deferred_free(mi_deferred_free_fun* deferred_free);
|
||||
void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg);
|
||||
|
||||
/// Type of output functions.
|
||||
/// @param msg Message to output.
|
||||
/// @param arg Argument that was passed at registration to hold extra state.
|
||||
///
|
||||
/// @see mi_register_output()
|
||||
typedef void (mi_output_fun)(const char* msg);
|
||||
typedef void (mi_output_fun)(const char* msg, void* arg);
|
||||
|
||||
/// Register an output function.
|
||||
/// @param out The output function, use `NULL` to output to stdout.
|
||||
/// @param out The output function, use `NULL` to output to stderr.
|
||||
/// @param arg Argument that will be passed on to the output function.
|
||||
///
|
||||
/// 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;
|
||||
void mi_register_output(mi_output_fun* out, void* arg);
|
||||
|
||||
/// Type of error callback functions.
|
||||
/// @param err Error code (see mi_register_error() for a complete list).
|
||||
/// @param arg Argument that was passed at registration to hold extra state.
|
||||
///
|
||||
/// @see mi_register_error()
|
||||
typedef void (mi_error_fun)(int err, void* arg);
|
||||
|
||||
/// Register an error callback function.
|
||||
/// @param errfun The error function that is called on an error (use \a NULL for default)
|
||||
/// @param arg Extra argument that will be passed on to the error function.
|
||||
///
|
||||
/// The \a errfun function is called on an error in mimalloc after emitting
|
||||
/// an error message (through the output function). It as always legal to just
|
||||
/// return from the \a errfun function in which case allocation functions generally
|
||||
/// return \a NULL or ignore the condition. The default function only calls abort()
|
||||
/// when compiled in secure mode with an \a EFAULT error. The possible error
|
||||
/// codes are:
|
||||
/// * \a EAGAIN: Double free was detected (only in debug and secure mode).
|
||||
/// * \a EFAULT: Corrupted free list or meta-data was detected (only in debug and secure mode).
|
||||
/// * \a ENOMEM: Not enough memory available to satisfy the request.
|
||||
/// * \a EOVERFLOW: Too large a request, for example in mi_calloc(), the \a count and \a size parameters are too large.
|
||||
/// * \a EINVAL: Trying to free or re-allocate an invalid pointer.
|
||||
void mi_register_error(mi_error_fun* errfun, void* arg);
|
||||
|
||||
/// Is a pointer part of our heap?
|
||||
/// @param p The pointer to check.
|
||||
@ -367,18 +405,35 @@ void mi_register_output(mi_output_fun* out) mi_attr_noexcept;
|
||||
/// 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.
|
||||
|
||||
/// Reserve \a pages of huge OS pages (1GiB) evenly divided over \a numa_nodes nodes,
|
||||
/// but stops after at most `timeout_msecs` 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.
|
||||
/// @param numa_nodes The number of nodes do evenly divide the pages over, or 0 for using the actual number of NUMA nodes.
|
||||
/// @param timeout_msecs Maximum number of milli-seconds to try reserving, or 0 for no timeout.
|
||||
/// @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
|
||||
/// May quit before \a timeout_msecs are expired if it estimates it will take more than
|
||||
/// 1.5 times \a timeout_msecs. 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);
|
||||
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs);
|
||||
|
||||
/// Reserve \a pages of huge OS pages (1GiB) at a specific \a numa_node,
|
||||
/// but stops after at most `timeout_msecs` seconds.
|
||||
/// @param pages The number of 1GiB pages to reserve.
|
||||
/// @param numa_node The NUMA node where the memory is reserved (start at 0).
|
||||
/// @param timeout_msecs Maximum number of milli-seconds to try reserving, or 0 for no timeout.
|
||||
/// @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 timeout_msecs are expired if it estimates it will take more than
|
||||
/// 1.5 times \a timeout_msecs. 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_at(size_t pages, int numa_node, size_t timeout_msecs);
|
||||
|
||||
|
||||
/// Is the C runtime \a malloc API redirected?
|
||||
/// @returns \a true if all malloc API calls are redirected to mimalloc.
|
||||
@ -569,7 +624,10 @@ void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, siz
|
||||
|
||||
/// \defgroup typed Typed Macros
|
||||
///
|
||||
/// Typed allocation macros
|
||||
/// Typed allocation macros. For example:
|
||||
/// ```
|
||||
/// int* p = mi_malloc_tp(int)
|
||||
/// ```
|
||||
///
|
||||
/// \{
|
||||
|
||||
@ -702,13 +760,14 @@ typedef enum mi_option_e {
|
||||
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_segment_cache, ///< The number of segments per thread to keep cached.
|
||||
mi_option_page_reset, ///< Reset page memory after \a mi_option_reset_delay milliseconds when it becomes free.
|
||||
mi_option_segment_reset, ///< Experimental
|
||||
mi_option_reset_delay, ///< Delay in milli-seconds before resetting a page (100ms by default)
|
||||
mi_option_use_numa_nodes, ///< Pretend there are at most N NUMA nodes
|
||||
mi_option_reset_decommits, ///< 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_os_tag, ///< OS tag to assign to mimalloc'd memory
|
||||
_mi_option_last
|
||||
} mi_option_t;
|
||||
|
||||
@ -751,18 +810,51 @@ void mi_free_size(void* p, size_t size);
|
||||
void mi_free_size_aligned(void* p, size_t size, size_t alignment);
|
||||
void mi_free_aligned(void* p, size_t alignment);
|
||||
|
||||
/// raise `std::bad_alloc` exception on failure.
|
||||
/// \}
|
||||
|
||||
/// \defgroup cpp C++ wrappers
|
||||
///
|
||||
/// `mi_` prefixed implementations of various allocation functions
|
||||
/// that use C++ semantics on out-of-memory, generally calling
|
||||
/// `std::get_new_handler` and raising a `std::bad_alloc` exception on failure.
|
||||
///
|
||||
/// Note: use the `mimalloc-new-delete.h` header to override the \a new
|
||||
/// and \a delete operators globally. The wrappers here are mostly
|
||||
/// for convience for library writers that need to interface with
|
||||
/// mimalloc from C++.
|
||||
///
|
||||
/// \{
|
||||
|
||||
/// like mi_malloc(), but when out of memory, use `std::get_new_handler` and raise `std::bad_alloc` exception on failure.
|
||||
void* mi_new(std::size_t n) noexcept(false);
|
||||
|
||||
/// raise `std::bad_alloc` exception on failure.
|
||||
/// like mi_mallocn(), but when out of memory, use `std::get_new_handler` and raise `std::bad_alloc` exception on failure.
|
||||
void* mi_new_n(size_t count, size_t size) noexcept(false);
|
||||
|
||||
/// like mi_malloc_aligned(), but when out of memory, use `std::get_new_handler` and raise `std::bad_alloc` exception on failure.
|
||||
void* mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false);
|
||||
|
||||
/// return `NULL` on failure.
|
||||
/// like `mi_malloc`, but when out of memory, use `std::get_new_handler` but return \a NULL on failure.
|
||||
void* mi_new_nothrow(size_t n);
|
||||
``
|
||||
/// return `NULL` on failure.
|
||||
|
||||
/// like `mi_malloc_aligned`, but when out of memory, use `std::get_new_handler` but return \a NULL on failure.
|
||||
void* mi_new_aligned_nothrow(size_t n, size_t alignment);
|
||||
|
||||
/// like mi_realloc(), but when out of memory, use `std::get_new_handler` and raise `std::bad_alloc` exception on failure.
|
||||
void* mi_new_realloc(void* p, size_t newsize);
|
||||
|
||||
/// like mi_reallocn(), but when out of memory, use `std::get_new_handler` and raise `std::bad_alloc` exception on failure.
|
||||
void* mi_new_reallocn(void* p, size_t newcount, size_t size);
|
||||
|
||||
/// \a std::allocator implementation for mimalloc for use in STL containers.
|
||||
/// For example:
|
||||
/// ```
|
||||
/// std::vector<int, mi_stl_allocator<int> > vec;
|
||||
/// vec.push_back(1);
|
||||
/// vec.pop_back();
|
||||
/// ```
|
||||
template<class T> struct mi_stl_allocator { }
|
||||
|
||||
/// \}
|
||||
|
||||
/*! \page build Building
|
||||
@ -774,7 +866,7 @@ git clone https://github.com/microsoft/mimalloc
|
||||
|
||||
## Windows
|
||||
|
||||
Open `ide/vs2017/mimalloc.sln` in Visual Studio 2017 and build.
|
||||
Open `ide/vs2019/mimalloc.sln` in Visual Studio 2019 and build (or `ide/vs2017/mimalloc.sln`).
|
||||
The `mimalloc` project builds a static library (in `out/msvc-x64`), while the
|
||||
`mimalloc-override` project builds a DLL for overriding malloc
|
||||
in the entire program.
|
||||
@ -826,6 +918,7 @@ Notes:
|
||||
|
||||
/*! \page using Using the library
|
||||
|
||||
### Build
|
||||
|
||||
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,
|
||||
@ -849,6 +942,19 @@ target_link_libraries(myapp PUBLIC mimalloc-static)
|
||||
```
|
||||
to link with the static library. See `test\CMakeLists.txt` for an example.
|
||||
|
||||
### C++
|
||||
For best performance in C++ programs, it is also recommended to override the
|
||||
global `new` and `delete` operators. For convience, mimalloc provides
|
||||
[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project.
|
||||
|
||||
In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator`
|
||||
interface. For example:
|
||||
```
|
||||
std::vector<some_struct, mi_stl_allocator<some_struct>> vec;
|
||||
vec.push_back(some_struct());
|
||||
```
|
||||
|
||||
### Statistics
|
||||
|
||||
You can pass environment variables to print verbose messages (`MIMALLOC_VERBOSE=1`)
|
||||
and statistics (`MIMALLOC_SHOW_STATS=1`) (in the debug version):
|
||||
@ -897,20 +1003,33 @@ See \ref overrides for more info.
|
||||
|
||||
/*! \page environment Environment Options
|
||||
|
||||
You can set further options either programmatically
|
||||
(using [`mi_option_set`](https://microsoft.github.io/mimalloc/group__options.html)),
|
||||
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.
|
||||
- `MIMALLOC_VERBOSE=1`: show verbose messages.
|
||||
- `MIMALLOC_SHOW_ERRORS=1`: show error and warning messages.
|
||||
- `MIMALLOC_PAGE_RESET=1`: reset (or purge) OS pages when not in use. This can reduce
|
||||
memory fragmentation in long running (server) programs. If performance is impacted,
|
||||
`MIMALLOC_RESET_DELAY=`_msecs_ can be set higher (100ms by default) to make the page
|
||||
reset occur less frequently.
|
||||
- `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 (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead when possible).
|
||||
- `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.
|
||||
Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting
|
||||
`MIMALLOC_EAGER_COMMIT_DELAY=N` (with usually `N` as 1) to delay the initial `N` segments
|
||||
of a thread to not allocate in the huge OS pages; this prevents threads that are short lived
|
||||
and allocate just a little to take up space in the huge OS page area (which cannot be reset).
|
||||
|
||||
[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
|
||||
@ -960,25 +1079,28 @@ 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 (using the `/MD` or `/MDd` switch).
|
||||
Overriding on Windows is robust but requires that you 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.
|
||||
in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency).
|
||||
The redirection DLL ensures that all calls to the C runtime malloc API get redirected to
|
||||
mimalloc (in `mimalloc-override.dll`).
|
||||
|
||||
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.
|
||||
for an example on how to use this. For best performance on Windows with C++, it
|
||||
is highly recommended to also override the `new`/`delete` operations (by including
|
||||
[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) a single(!) source file in your project).
|
||||
|
||||
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.
|
||||
overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was 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)
|
||||
(Note: in principle, it is possible to patch existing executables
|
||||
that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the `mimalloc-override.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
|
||||
|
||||
On Unix systems, you can also statically link with _mimalloc_ to override the standard
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -105,6 +105,7 @@ $(document).ready(function(){initNavTree('annotated.html','');});
|
||||
<div class="textblock">Here are the data structures with brief descriptions:</div><div class="directory">
|
||||
<table class="directory">
|
||||
<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="group__analysis.html#structmi__heap__area__t" target="_self">mi_heap_area_t</a></td><td class="desc">An area of heap space contains blocks of a single size </td></tr>
|
||||
<tr id="row_1_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="group__cpp.html#structmi__stl__allocator" target="_self">mi_stl_allocator</a></td><td class="desc"><em>std::allocator</em> implementation for mimalloc for use in STL containers </td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
|
@ -1,4 +1,5 @@
|
||||
var annotated_dup =
|
||||
[
|
||||
[ "mi_heap_area_t", "group__analysis.html#structmi__heap__area__t", "group__analysis_structmi__heap__area__t" ]
|
||||
[ "mi_heap_area_t", "group__analysis.html#structmi__heap__area__t", "group__analysis_structmi__heap__area__t" ],
|
||||
[ "mi_stl_allocator", "group__cpp.html#structmi__stl__allocator", null ]
|
||||
];
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -103,7 +103,7 @@ $(document).ready(function(){initNavTree('build.html','');});
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>Checkout the sources from Github: </p><div class="fragment"><div class="line">git clone https:<span class="comment">//github.com/microsoft/mimalloc</span></div></div><!-- fragment --><h2>Windows</h2>
|
||||
<p>Open <code>ide/vs2017/mimalloc.sln</code> in Visual Studio 2017 and build. The <code>mimalloc</code> project builds a static library (in <code>out/msvc-x64</code>), while the <code>mimalloc-override</code> project builds a DLL for overriding malloc in the entire program.</p>
|
||||
<p>Open <code>ide/vs2019/mimalloc.sln</code> in Visual Studio 2019 and build (or <code>ide/vs2017/mimalloc.sln</code>). The <code>mimalloc</code> project builds a static library (in <code>out/msvc-x64</code>), while the <code>mimalloc-override</code> project builds a DLL for overriding malloc in the entire program.</p>
|
||||
<h2>macOS, Linux, BSD, etc.</h2>
|
||||
<p>We use <a href="https://cmake.org"><code>cmake</code></a><sup>1</sup> as the build system:</p>
|
||||
<div class="fragment"><div class="line">> mkdir -p out/release</div><div class="line">> cd out/release</div><div class="line">> cmake ../..</div><div class="line">> make</div></div><!-- fragment --><p> This builds the library as a shared (dynamic) library (<code>.so</code> or <code>.dylib</code>), a static library (<code>.a</code>), and as a single object file (<code>.o</code>).</p>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -105,10 +105,10 @@ $(document).ready(function(){initNavTree('classes.html','');});
|
||||
<div class="qindex"><a class="qindex" href="#letter_m">m</a></div>
|
||||
<table class="classindex">
|
||||
<tr><td rowspan="2" valign="bottom"><a name="letter_m"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">  m  </div></td></tr></table>
|
||||
</td><td></td></tr>
|
||||
<tr><td></td><td></td></tr>
|
||||
<tr><td valign="top"><a class="el" href="group__analysis.html#structmi__heap__area__t">mi_heap_area_t</a>   </td><td></td></tr>
|
||||
<tr><td></td><td></td></tr>
|
||||
</td><td valign="top"><a class="el" href="group__cpp.html#structmi__stl__allocator">mi_stl_allocator</a>   </td><td></td></tr>
|
||||
<tr><td></td><td></td><td></td></tr>
|
||||
<tr><td valign="top"><a class="el" href="group__analysis.html#structmi__heap__area__t">mi_heap_area_t</a>   </td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td></td></tr>
|
||||
</table>
|
||||
<div class="qindex"><a class="qindex" href="#letter_m">m</a></div>
|
||||
</div><!-- contents -->
|
||||
|
127
docs/environment.html
Normal file
127
docs/environment.html
Normal file
@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>mi-malloc: Environment Options</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="resize.js"></script>
|
||||
<script type="text/javascript" src="navtreedata.js"></script>
|
||||
<script type="text/javascript" src="navtree.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(initResizable);
|
||||
/* @license-end */</script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function() { init_search(); });
|
||||
/* @license-end */
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="mimalloc-doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
<span class="left">
|
||||
<img id="MSearchSelect" src="search/mag_sel.png"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
alt=""/>
|
||||
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
||||
onfocus="searchBox.OnSearchFieldFocus(true)"
|
||||
onblur="searchBox.OnSearchFieldFocus(false)"
|
||||
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
||||
</span><span class="right">
|
||||
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.15 -->
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
/* @license-end */
|
||||
</script>
|
||||
</div><!-- top -->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||
<div id="nav-tree">
|
||||
<div id="nav-tree-contents">
|
||||
<div id="nav-sync" class="sync"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="splitbar" style="-moz-user-select:none;"
|
||||
class="ui-resizable-handle">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function(){initNavTree('environment.html','');});
|
||||
/* @license-end */
|
||||
</script>
|
||||
<div id="doc-content">
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="PageDoc"><div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Environment Options </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>You can set further options either programmatically (using <a href="https://microsoft.github.io/mimalloc/group__options.html"><code>mi_option_set</code></a>), or via environment variables.</p>
|
||||
<ul>
|
||||
<li><code>MIMALLOC_SHOW_STATS=1</code>: show statistics when the program terminates.</li>
|
||||
<li><code>MIMALLOC_VERBOSE=1</code>: show verbose messages.</li>
|
||||
<li><code>MIMALLOC_SHOW_ERRORS=1</code>: show error and warning messages.</li>
|
||||
<li><code>MIMALLOC_PAGE_RESET=1</code>: reset (or purge) OS pages when not in use. This can reduce memory fragmentation in long running (server) programs. If performance is impacted, <code>MIMALLOC_RESET_DELAY=</code>_msecs_ can be set higher (100ms by default) to make the page reset occur less frequently.</li>
|
||||
<li><code>MIMALLOC_LARGE_OS_PAGES=1</code>: use large OS pages when available; for some workloads this can significantly improve performance. Use <code>MIMALLOC_VERBOSE</code> to check if the large OS pages are enabled – usually one needs to explicitly allow large OS pages (as on <a href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017">Windows</a> and <a href="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">Linux</a>). 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 (for that reason, we generally recommend to use <code>MIMALLOC_RESERVE_HUGE_OS_PAGES</code> instead when possible).</li>
|
||||
<li><code>MIMALLOC_EAGER_REGION_COMMIT=1</code>: 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.</li>
|
||||
<li><code>MIMALLOC_RESERVE_HUGE_OS_PAGES=N</code>: 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 <code>MIMALLOC_LARGE_OS_PAGES</code> 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. Note that we usually need to explicitly enable huge OS pages (as on <a href="https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows?view=sql-server-2017">Windows</a> and <a href="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">Linux</a>)). With huge OS pages, it may be beneficial to set the setting <code>MIMALLOC_EAGER_COMMIT_DELAY=N</code> (with usually <code>N</code> as 1) to delay the initial <code>N</code> segments of a thread to not allocate in the huge OS pages; this prevents threads that are short lived and allocate just a little to take up space in the huge OS page area (which cannot be reset). </li>
|
||||
</ul>
|
||||
</div></div><!-- PageDoc -->
|
||||
</div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- start footer part -->
|
||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||
<ul>
|
||||
<li class="footer">Generated by
|
||||
<a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.15 </li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
396
docs/group__cpp.html
Normal file
396
docs/group__cpp.html
Normal file
@ -0,0 +1,396 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>mi-malloc: C++ wrappers</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="resize.js"></script>
|
||||
<script type="text/javascript" src="navtreedata.js"></script>
|
||||
<script type="text/javascript" src="navtree.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(initResizable);
|
||||
/* @license-end */</script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function() { init_search(); });
|
||||
/* @license-end */
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="mimalloc-doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
<span class="left">
|
||||
<img id="MSearchSelect" src="search/mag_sel.png"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
alt=""/>
|
||||
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
||||
onfocus="searchBox.OnSearchFieldFocus(true)"
|
||||
onblur="searchBox.OnSearchFieldFocus(false)"
|
||||
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
||||
</span><span class="right">
|
||||
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.15 -->
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
/* @license-end */
|
||||
</script>
|
||||
</div><!-- top -->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||
<div id="nav-tree">
|
||||
<div id="nav-tree-contents">
|
||||
<div id="nav-sync" class="sync"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="splitbar" style="-moz-user-select:none;"
|
||||
class="ui-resizable-handle">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function(){initNavTree('group__cpp.html','');});
|
||||
/* @license-end */
|
||||
</script>
|
||||
<div id="doc-content">
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="summary">
|
||||
<a href="#nested-classes">Data Structures</a> |
|
||||
<a href="#func-members">Functions</a> </div>
|
||||
<div class="headertitle">
|
||||
<div class="title">C++ wrappers</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
|
||||
<p><code>mi_</code> prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling <code>std::get_new_handler</code> and raising a <code>std::bad_alloc</code> exception on failure.
|
||||
<a href="#details">More...</a></p>
|
||||
<table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="nested-classes"></a>
|
||||
Data Structures</h2></td></tr>
|
||||
<tr class="memitem:structmi__stl__allocator"><td class="memItemLeft" align="right" valign="top">struct  </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#structmi__stl__allocator">mi_stl_allocator< T ></a></td></tr>
|
||||
<tr class="memdesc:structmi__stl__allocator"><td class="mdescLeft"> </td><td class="mdescRight"><em>std::allocator</em> implementation for mimalloc for use in STL containers. <a href="group__cpp.html#structmi__stl__allocator">More...</a><br /></td></tr>
|
||||
<tr class="separator:structmi__stl__allocator"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table><table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
|
||||
Functions</h2></td></tr>
|
||||
<tr class="memitem:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545">mi_new</a> (std::size_t n) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaad048a9fce3d02c5909cd05c6ec24545"><td class="mdescLeft"> </td><td class="mdescRight">like <a class="el" href="group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a" title="Allocate size bytes.">mi_malloc()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. <a href="#gaad048a9fce3d02c5909cd05c6ec24545">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81">mi_new_n</a> (size_t count, size_t size) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="mdescLeft"> </td><td class="mdescRight">like <a class="el" href="group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6" title="Allocate count elements of size bytes.">mi_mallocn()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. <a href="#gae7bc4f56cd57ed3359060ff4f38bda81">More...</a><br /></td></tr>
|
||||
<tr class="separator:gae7bc4f56cd57ed3359060ff4f38bda81"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3">mi_new_aligned</a> (std::size_t n, std::align_val_t alignment) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="mdescLeft"> </td><td class="mdescRight">like <a class="el" href="group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56" title="Allocate size bytes aligned by alignment.">mi_malloc_aligned()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. <a href="#gaef2c2bdb4f70857902d3c8903ac095f3">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a">mi_new_nothrow</a> (size_t n)</td></tr>
|
||||
<tr class="memdesc:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="mdescLeft"> </td><td class="mdescRight">like <code>mi_malloc</code>, but when out of memory, use <code>std::get_new_handler</code> but return <em>NULL</em> on failure. <a href="#gaeaded64eda71ed6b1d569d3e723abc4a">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gab5e29558926d934c3f1cae8c815f942c"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gab5e29558926d934c3f1cae8c815f942c">mi_new_aligned_nothrow</a> (size_t n, size_t alignment)</td></tr>
|
||||
<tr class="memdesc:gab5e29558926d934c3f1cae8c815f942c"><td class="mdescLeft"> </td><td class="mdescRight">like <code>mi_malloc_aligned</code>, but when out of memory, use <code>std::get_new_handler</code> but return <em>NULL</em> on failure. <a href="#gab5e29558926d934c3f1cae8c815f942c">More...</a><br /></td></tr>
|
||||
<tr class="separator:gab5e29558926d934c3f1cae8c815f942c"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaab78a32f55149e9fbf432d5288e38e1e"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e">mi_new_realloc</a> (void *p, size_t newsize)</td></tr>
|
||||
<tr class="memdesc:gaab78a32f55149e9fbf432d5288e38e1e"><td class="mdescLeft"> </td><td class="mdescRight">like <a class="el" href="group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6" title="Re-allocate memory to newsize bytes.">mi_realloc()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. <a href="#gaab78a32f55149e9fbf432d5288e38e1e">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaab78a32f55149e9fbf432d5288e38e1e"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga756f4b2bc6a7ecd0a90baea8e90c7907"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907">mi_new_reallocn</a> (void *p, size_t newcount, size_t size)</td></tr>
|
||||
<tr class="memdesc:ga756f4b2bc6a7ecd0a90baea8e90c7907"><td class="mdescLeft"> </td><td class="mdescRight">like <a class="el" href="group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853" title="Re-allocate memory to count elements of size bytes.">mi_reallocn()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. <a href="#ga756f4b2bc6a7ecd0a90baea8e90c7907">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga756f4b2bc6a7ecd0a90baea8e90c7907"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table>
|
||||
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
|
||||
<p><code>mi_</code> prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling <code>std::get_new_handler</code> and raising a <code>std::bad_alloc</code> exception on failure. </p>
|
||||
<p>Note: use the <code>mimalloc-new-delete.h</code> header to override the <em>new</em> and <em>delete</em> operators globally. The wrappers here are mostly for convience for library writers that need to interface with mimalloc from C++. </p>
|
||||
<hr/><h2 class="groupheader">Data Structure Documentation</h2>
|
||||
<a name="structmi__stl__allocator" id="structmi__stl__allocator"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#structmi__stl__allocator">◆ </a></span>mi_stl_allocator</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">struct mi_stl_allocator</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
<div class="textblock"><h3>template<class T><br />
|
||||
struct mi_stl_allocator< T ></h3>
|
||||
|
||||
<p><em>std::allocator</em> implementation for mimalloc for use in STL containers. </p>
|
||||
<p>For example: </p><div class="fragment"><div class="line">std::vector<int, mi_stl_allocator<int> > vec;</div><div class="line">vec.push_back(1);</div><div class="line">vec.pop_back();</div></div><!-- fragment --> </div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="groupheader">Function Documentation</h2>
|
||||
<a id="gaad048a9fce3d02c5909cd05c6ec24545"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaad048a9fce3d02c5909cd05c6ec24545">◆ </a></span>mi_new()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">std::size_t </td>
|
||||
<td class="paramname"><em>n</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <a class="el" href="group__malloc.html#ga3406e8b168bc74c8637b11571a6da83a" title="Allocate size bytes.">mi_malloc()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaef2c2bdb4f70857902d3c8903ac095f3"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaef2c2bdb4f70857902d3c8903ac095f3">◆ </a></span>mi_new_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">std::size_t </td>
|
||||
<td class="paramname"><em>n</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">std::align_val_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <a class="el" href="group__aligned.html#ga68930196751fa2cca9e1fd0d71bade56" title="Allocate size bytes aligned by alignment.">mi_malloc_aligned()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gab5e29558926d934c3f1cae8c815f942c"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gab5e29558926d934c3f1cae8c815f942c">◆ </a></span>mi_new_aligned_nothrow()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_aligned_nothrow </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>n</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <code>mi_malloc_aligned</code>, but when out of memory, use <code>std::get_new_handler</code> but return <em>NULL</em> on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gae7bc4f56cd57ed3359060ff4f38bda81"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gae7bc4f56cd57ed3359060ff4f38bda81">◆ </a></span>mi_new_n()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_n </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>count</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <a class="el" href="group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6" title="Allocate count elements of size bytes.">mi_mallocn()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaeaded64eda71ed6b1d569d3e723abc4a"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaeaded64eda71ed6b1d569d3e723abc4a">◆ </a></span>mi_new_nothrow()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_nothrow </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>n</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <code>mi_malloc</code>, but when out of memory, use <code>std::get_new_handler</code> but return <em>NULL</em> on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaab78a32f55149e9fbf432d5288e38e1e"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaab78a32f55149e9fbf432d5288e38e1e">◆ </a></span>mi_new_realloc()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_realloc </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <a class="el" href="group__malloc.html#gaf11eb497da57bdfb2de65eb191c69db6" title="Re-allocate memory to newsize bytes.">mi_realloc()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga756f4b2bc6a7ecd0a90baea8e90c7907"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga756f4b2bc6a7ecd0a90baea8e90c7907">◆ </a></span>mi_new_reallocn()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_reallocn </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>like <a class="el" href="group__malloc.html#ga61d57b4144ba24fba5c1e9b956d13853" title="Re-allocate memory to count elements of size bytes.">mi_reallocn()</a>, but when out of memory, use <code>std::get_new_handler</code> and raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- start footer part -->
|
||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||
<ul>
|
||||
<li class="footer">Generated by
|
||||
<a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.15 </li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
11
docs/group__cpp.js
Normal file
11
docs/group__cpp.js
Normal file
@ -0,0 +1,11 @@
|
||||
var group__cpp =
|
||||
[
|
||||
[ "mi_stl_allocator", "group__cpp.html#structmi__stl__allocator", null ],
|
||||
[ "mi_new", "group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545", null ],
|
||||
[ "mi_new_aligned", "group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3", null ],
|
||||
[ "mi_new_aligned_nothrow", "group__cpp.html#gab5e29558926d934c3f1cae8c815f942c", null ],
|
||||
[ "mi_new_n", "group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81", null ],
|
||||
[ "mi_new_nothrow", "group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a", null ],
|
||||
[ "mi_new_realloc", "group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e", null ],
|
||||
[ "mi_new_reallocn", "group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907", null ]
|
||||
];
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -118,12 +118,15 @@ Macros</h2></td></tr>
|
||||
</table><table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="typedef-members"></a>
|
||||
Typedefs</h2></td></tr>
|
||||
<tr class="memitem:ga22213691c3ce5ab4d91b24aff1023529"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga22213691c3ce5ab4d91b24aff1023529">mi_deferred_free_fun</a>(bool force, unsigned long long heartbeat)</td></tr>
|
||||
<tr class="memdesc:ga22213691c3ce5ab4d91b24aff1023529"><td class="mdescLeft"> </td><td class="mdescRight">Type of deferred free functions. <a href="#ga22213691c3ce5ab4d91b24aff1023529">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga22213691c3ce5ab4d91b24aff1023529"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga2bed6d40b74591a67f81daea4b4a246f"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a>(const char *msg)</td></tr>
|
||||
<tr class="memdesc:ga2bed6d40b74591a67f81daea4b4a246f"><td class="mdescLeft"> </td><td class="mdescRight">Type of output functions. <a href="#ga2bed6d40b74591a67f81daea4b4a246f">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga2bed6d40b74591a67f81daea4b4a246f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga299dae78d25ce112e384a98b7309c5be"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga299dae78d25ce112e384a98b7309c5be">mi_deferred_free_fun</a>(bool force, unsigned long long heartbeat, void *arg)</td></tr>
|
||||
<tr class="memdesc:ga299dae78d25ce112e384a98b7309c5be"><td class="mdescLeft"> </td><td class="mdescRight">Type of deferred free functions. <a href="#ga299dae78d25ce112e384a98b7309c5be">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga299dae78d25ce112e384a98b7309c5be"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gad823d23444a4b77a40f66bf075a98a0c"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a>(const char *msg, void *arg)</td></tr>
|
||||
<tr class="memdesc:gad823d23444a4b77a40f66bf075a98a0c"><td class="mdescLeft"> </td><td class="mdescRight">Type of output functions. <a href="#gad823d23444a4b77a40f66bf075a98a0c">More...</a><br /></td></tr>
|
||||
<tr class="separator:gad823d23444a4b77a40f66bf075a98a0c"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga251d369cda3f1c2a955c555486ed90e5"><td class="memItemLeft" align="right" valign="top">typedef void() </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a>(int err, void *arg)</td></tr>
|
||||
<tr class="memdesc:ga251d369cda3f1c2a955c555486ed90e5"><td class="mdescLeft"> </td><td class="mdescRight">Type of error callback functions. <a href="#ga251d369cda3f1c2a955c555486ed90e5">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga251d369cda3f1c2a955c555486ed90e5"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table><table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
|
||||
Functions</h2></td></tr>
|
||||
@ -142,9 +145,12 @@ Functions</h2></td></tr>
|
||||
<tr class="memitem:ga421430e2226d7d468529cec457396756"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga421430e2226d7d468529cec457396756">mi_collect</a> (bool force)</td></tr>
|
||||
<tr class="memdesc:ga421430e2226d7d468529cec457396756"><td class="mdescLeft"> </td><td class="mdescRight">Eagerly free memory. <a href="#ga421430e2226d7d468529cec457396756">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga421430e2226d7d468529cec457396756"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga8ca07ccff283956d71f48272f4fd5c01"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01">mi_stats_print</a> (<a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> *out)</td></tr>
|
||||
<tr class="memdesc:ga8ca07ccff283956d71f48272f4fd5c01"><td class="mdescLeft"> </td><td class="mdescRight">Print the main statistics. <a href="#ga8ca07ccff283956d71f48272f4fd5c01">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga8ca07ccff283956d71f48272f4fd5c01"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga2d126e5c62d3badc35445e5d84166df2"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga2d126e5c62d3badc35445e5d84166df2">mi_stats_print</a> (void *out)</td></tr>
|
||||
<tr class="memdesc:ga2d126e5c62d3badc35445e5d84166df2"><td class="mdescLeft"> </td><td class="mdescRight">Print the main statistics. <a href="#ga2d126e5c62d3badc35445e5d84166df2">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga2d126e5c62d3badc35445e5d84166df2"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga256cc6f13a142deabbadd954a217e228"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga256cc6f13a142deabbadd954a217e228">mi_stats_print</a> (<a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> *out, void *arg)</td></tr>
|
||||
<tr class="memdesc:ga256cc6f13a142deabbadd954a217e228"><td class="mdescLeft"> </td><td class="mdescRight">Print the main statistics. <a href="#ga256cc6f13a142deabbadd954a217e228">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga256cc6f13a142deabbadd954a217e228"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga3bb8468b8cfcc6e2a61d98aee85c5f99"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99">mi_stats_reset</a> (void)</td></tr>
|
||||
<tr class="memdesc:ga3bb8468b8cfcc6e2a61d98aee85c5f99"><td class="mdescLeft"> </td><td class="mdescRight">Reset statistics. <a href="#ga3bb8468b8cfcc6e2a61d98aee85c5f99">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga3bb8468b8cfcc6e2a61d98aee85c5f99"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
@ -157,21 +163,27 @@ Functions</h2></td></tr>
|
||||
<tr class="memitem:ga0ae4581e85453456a0d658b2b98bf7bf"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf">mi_thread_done</a> (void)</td></tr>
|
||||
<tr class="memdesc:ga0ae4581e85453456a0d658b2b98bf7bf"><td class="mdescLeft"> </td><td class="mdescRight">Uninitialize mimalloc on a thread. <a href="#ga0ae4581e85453456a0d658b2b98bf7bf">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga0ae4581e85453456a0d658b2b98bf7bf"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga489670a15d1a257ab4639e645ee4612a"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga489670a15d1a257ab4639e645ee4612a">mi_thread_stats_print</a> (<a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> *out)</td></tr>
|
||||
<tr class="memdesc:ga489670a15d1a257ab4639e645ee4612a"><td class="mdescLeft"> </td><td class="mdescRight">Print out heap statistics for this thread. <a href="#ga489670a15d1a257ab4639e645ee4612a">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga489670a15d1a257ab4639e645ee4612a"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga24dc9cc6fca8daa2aa30aa8025467ce2"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2">mi_register_deferred_free</a> (<a class="el" href="group__extended.html#ga22213691c3ce5ab4d91b24aff1023529">mi_deferred_free_fun</a> *deferred_free)</td></tr>
|
||||
<tr class="memdesc:ga24dc9cc6fca8daa2aa30aa8025467ce2"><td class="mdescLeft"> </td><td class="mdescRight">Register a deferred free function. <a href="#ga24dc9cc6fca8daa2aa30aa8025467ce2">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga24dc9cc6fca8daa2aa30aa8025467ce2"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga84a0c8b401e42eb5b1bce156852f44c5"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5">mi_register_output</a> (<a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> *out) mi_attr_noexcept</td></tr>
|
||||
<tr class="memdesc:ga84a0c8b401e42eb5b1bce156852f44c5"><td class="mdescLeft"> </td><td class="mdescRight">Register an output function. <a href="#ga84a0c8b401e42eb5b1bce156852f44c5">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga84a0c8b401e42eb5b1bce156852f44c5"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gab1dac8476c46cb9eecab767eb40c1525"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gab1dac8476c46cb9eecab767eb40c1525">mi_thread_stats_print_out</a> (<a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> *out, void *arg)</td></tr>
|
||||
<tr class="memdesc:gab1dac8476c46cb9eecab767eb40c1525"><td class="mdescLeft"> </td><td class="mdescRight">Print out heap statistics for this thread. <a href="#gab1dac8476c46cb9eecab767eb40c1525">More...</a><br /></td></tr>
|
||||
<tr class="separator:gab1dac8476c46cb9eecab767eb40c1525"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga3460a6ca91af97be4058f523d3cb8ece"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece">mi_register_deferred_free</a> (<a class="el" href="group__extended.html#ga299dae78d25ce112e384a98b7309c5be">mi_deferred_free_fun</a> *deferred_free, void *arg)</td></tr>
|
||||
<tr class="memdesc:ga3460a6ca91af97be4058f523d3cb8ece"><td class="mdescLeft"> </td><td class="mdescRight">Register a deferred free function. <a href="#ga3460a6ca91af97be4058f523d3cb8ece">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga3460a6ca91af97be4058f523d3cb8ece"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gae5b17ff027cd2150b43a33040250cf3f"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gae5b17ff027cd2150b43a33040250cf3f">mi_register_output</a> (<a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> *out, void *arg)</td></tr>
|
||||
<tr class="memdesc:gae5b17ff027cd2150b43a33040250cf3f"><td class="mdescLeft"> </td><td class="mdescRight">Register an output function. <a href="#gae5b17ff027cd2150b43a33040250cf3f">More...</a><br /></td></tr>
|
||||
<tr class="separator:gae5b17ff027cd2150b43a33040250cf3f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45">mi_register_error</a> (<a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a> *errfun, void *arg)</td></tr>
|
||||
<tr class="memdesc:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="mdescLeft"> </td><td class="mdescRight">Register an error callback function. <a href="#gaa1d55e0e894be240827e5d87ec3a1f45">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaa1d55e0e894be240827e5d87ec3a1f45"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="memItemLeft" align="right" valign="top">bool </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6">mi_is_in_heap_region</a> (const void *p)</td></tr>
|
||||
<tr class="memdesc:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="mdescLeft"> </td><td class="mdescRight">Is a pointer part of our heap? <a href="#ga5f071b10d4df1c3658e04e7fd67a94e6">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga5f071b10d4df1c3658e04e7fd67a94e6"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga2664f36a2dd557741c429cb799f04641"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga2664f36a2dd557741c429cb799f04641">mi_reserve_huge_os_pages</a> (size_t pages, double max_secs, size_t *pages_reserved)</td></tr>
|
||||
<tr class="memdesc:ga2664f36a2dd557741c429cb799f04641"><td class="mdescLeft"> </td><td class="mdescRight">Reserve <em>pages</em> of huge OS pages (1GiB) but stops after at most <code>max_secs</code> seconds. <a href="#ga2664f36a2dd557741c429cb799f04641">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga2664f36a2dd557741c429cb799f04641"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50">mi_reserve_huge_os_pages_interleave</a> (size_t pages, size_t numa_nodes, size_t timeout_msecs)</td></tr>
|
||||
<tr class="memdesc:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="mdescLeft"> </td><td class="mdescRight">Reserve <em>pages</em> of huge OS pages (1GiB) evenly divided over <em>numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. <a href="#ga3132f521fb756fc0e8ec0b74fb58df50">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga7795a13d20087447281858d2c771cca1"><td class="memItemLeft" align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#ga7795a13d20087447281858d2c771cca1">mi_reserve_huge_os_pages_at</a> (size_t pages, int numa_node, size_t timeout_msecs)</td></tr>
|
||||
<tr class="memdesc:ga7795a13d20087447281858d2c771cca1"><td class="mdescLeft"> </td><td class="mdescRight">Reserve <em>pages</em> of huge OS pages (1GiB) at a specific <em>numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. <a href="#ga7795a13d20087447281858d2c771cca1">More...</a><br /></td></tr>
|
||||
<tr class="separator:ga7795a13d20087447281858d2c771cca1"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaad25050b19f30cd79397b227e0157a3f"><td class="memItemLeft" align="right" valign="top">bool </td><td class="memItemRight" valign="bottom"><a class="el" href="group__extended.html#gaad25050b19f30cd79397b227e0157a3f">mi_is_redirected</a> ()</td></tr>
|
||||
<tr class="memdesc:gaad25050b19f30cd79397b227e0157a3f"><td class="mdescLeft"> </td><td class="mdescRight">Is the C runtime <em>malloc</em> API redirected? <a href="#gaad25050b19f30cd79397b227e0157a3f">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaad25050b19f30cd79397b227e0157a3f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
@ -196,14 +208,14 @@ Functions</h2></td></tr>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="groupheader">Typedef Documentation</h2>
|
||||
<a id="ga22213691c3ce5ab4d91b24aff1023529"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga22213691c3ce5ab4d91b24aff1023529">◆ </a></span>mi_deferred_free_fun</h2>
|
||||
<a id="ga299dae78d25ce112e384a98b7309c5be"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga299dae78d25ce112e384a98b7309c5be">◆ </a></span>mi_deferred_free_fun</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat)</td>
|
||||
<td class="memname">typedef void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
@ -212,22 +224,47 @@ Functions</h2></td></tr>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">force</td><td>If <em>true</em> all outstanding items should be freed. </td></tr>
|
||||
<tr><td class="paramname">heartbeat</td><td>A monotonically increasing count.</td></tr>
|
||||
<tr><td class="paramname">heartbeat</td><td>A monotonically increasing count. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that was passed at registration to hold extra state.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#ga24dc9cc6fca8daa2aa30aa8025467ce2" title="Register a deferred free function.">mi_register_deferred_free</a> </dd></dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece" title="Register a deferred free function.">mi_register_deferred_free</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga2bed6d40b74591a67f81daea4b4a246f"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga2bed6d40b74591a67f81daea4b4a246f">◆ </a></span>mi_output_fun</h2>
|
||||
<a id="ga251d369cda3f1c2a955c555486ed90e5"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga251d369cda3f1c2a955c555486ed90e5">◆ </a></span>mi_error_fun</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">typedef void() mi_output_fun(const char *msg)</td>
|
||||
<td class="memname">typedef void() mi_error_fun(int err, void *arg)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Type of error callback functions. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">err</td><td>Error code (see <a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45" title="Register an error callback function.">mi_register_error()</a> for a complete list). </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that was passed at registration to hold extra state.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45" title="Register an error callback function.">mi_register_error()</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gad823d23444a4b77a40f66bf075a98a0c"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gad823d23444a4b77a40f66bf075a98a0c">◆ </a></span>mi_output_fun</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">typedef void() mi_output_fun(const char *msg, void *arg)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
@ -235,11 +272,12 @@ Functions</h2></td></tr>
|
||||
<p>Type of output functions. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">msg</td><td>Message to output.</td></tr>
|
||||
<tr><td class="paramname">msg</td><td>Message to output. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that was passed at registration to hold extra state.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5" title="Register an output function.">mi_register_output()</a> </dd></dl>
|
||||
<dl class="section see"><dt>See also</dt><dd><a class="el" href="group__extended.html#gae5b17ff027cd2150b43a33040250cf3f" title="Register an output function.">mi_register_output()</a> </dd></dl>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -375,8 +413,8 @@ Functions</h2></td></tr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga24dc9cc6fca8daa2aa30aa8025467ce2"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga24dc9cc6fca8daa2aa30aa8025467ce2">◆ </a></span>mi_register_deferred_free()</h2>
|
||||
<a id="ga3460a6ca91af97be4058f523d3cb8ece"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga3460a6ca91af97be4058f523d3cb8ece">◆ </a></span>mi_register_deferred_free()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
@ -384,74 +422,14 @@ Functions</h2></td></tr>
|
||||
<tr>
|
||||
<td class="memname">void mi_register_deferred_free </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga22213691c3ce5ab4d91b24aff1023529">mi_deferred_free_fun</a> * </td>
|
||||
<td class="paramname"><em>deferred_free</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Register a deferred free function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">deferred_free</td><td>Address of a deferred free-ing function or <em>NULL</em> to unregister.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the <em>force</em> parameter is <em>true</em> all possible memory should be freed. The per-thread <em>heartbeat</em> parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The <em>deferred_free</em> function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one <em>deferred_free</em> function can be active. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga84a0c8b401e42eb5b1bce156852f44c5"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga84a0c8b401e42eb5b1bce156852f44c5">◆ </a></span>mi_register_output()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_register_output </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> * </td>
|
||||
<td class="paramname"><em>out</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Register an output function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">out</td><td>The output function, use <code>NULL</code> to output to stdout.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The <code>out</code> function is called to output any information from mimalloc, like verbose or warning messages. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga2664f36a2dd557741c429cb799f04641"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga2664f36a2dd557741c429cb799f04641">◆ </a></span>mi_reserve_huge_os_pages()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int mi_reserve_huge_os_pages </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>pages</em>, </td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga299dae78d25ce112e384a98b7309c5be">mi_deferred_free_fun</a> * </td>
|
||||
<td class="paramname"><em>deferred_free</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">double </td>
|
||||
<td class="paramname"><em>max_secs</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t * </td>
|
||||
<td class="paramname"><em>pages_reserved</em> </td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
@ -461,17 +439,189 @@ Functions</h2></td></tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Reserve <em>pages</em> of huge OS pages (1GiB) but stops after at most <code>max_secs</code> seconds. </p>
|
||||
<p>Register a deferred free function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">deferred_free</td><td>Address of a deferred free-ing function or <em>NULL</em> to unregister. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that will be passed on to the deferred free function.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the <em>force</em> parameter is <em>true</em> all possible memory should be freed. The per-thread <em>heartbeat</em> parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The <em>deferred_free</em> function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one <em>deferred_free</em> function can be active. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaa1d55e0e894be240827e5d87ec3a1f45"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaa1d55e0e894be240827e5d87ec3a1f45">◆ </a></span>mi_register_error()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_register_error </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga251d369cda3f1c2a955c555486ed90e5">mi_error_fun</a> * </td>
|
||||
<td class="paramname"><em>errfun</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Register an error callback function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">errfun</td><td>The error function that is called on an error (use <em>NULL</em> for default) </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Extra argument that will be passed on to the error function.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The <em>errfun</em> function is called on an error in mimalloc after emitting an error message (through the output function). It as always legal to just return from the <em>errfun</em> function in which case allocation functions generally return <em>NULL</em> or ignore the condition. The default function only calls abort() when compiled in secure mode with an <em>EFAULT</em> error. The possible error codes are:</p><ul>
|
||||
<li><em>EAGAIN:</em> Double free was detected (only in debug and secure mode).</li>
|
||||
<li><em>EFAULT:</em> Corrupted free list or meta-data was detected (only in debug and secure mode).</li>
|
||||
<li><em>ENOMEM:</em> Not enough memory available to satisfy the request.</li>
|
||||
<li><em>EOVERFLOW:</em> Too large a request, for example in <a class="el" href="group__malloc.html#ga97fedb4f7107c592fd7f0f0a8949a57d" title="Allocate zero-initialized count elements of size bytes.">mi_calloc()</a>, the <em>count</em> and <em>size</em> parameters are too large.</li>
|
||||
<li><em>EINVAL:</em> Trying to free or re-allocate an invalid pointer. </li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gae5b17ff027cd2150b43a33040250cf3f"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gae5b17ff027cd2150b43a33040250cf3f">◆ </a></span>mi_register_output()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_register_output </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> * </td>
|
||||
<td class="paramname"><em>out</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Register an output function. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">out</td><td>The output function, use <code>NULL</code> to output to stderr. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Argument that will be passed on to the output function.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The <code>out</code> function is called to output any information from mimalloc, like verbose or warning messages. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga7795a13d20087447281858d2c771cca1"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga7795a13d20087447281858d2c771cca1">◆ </a></span>mi_reserve_huge_os_pages_at()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int mi_reserve_huge_os_pages_at </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>pages</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">int </td>
|
||||
<td class="paramname"><em>numa_node</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>timeout_msecs</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Reserve <em>pages</em> of huge OS pages (1GiB) at a specific <em>numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">pages</td><td>The number of 1GiB pages to reserve. </td></tr>
|
||||
<tr><td class="paramname">max_secs</td><td>Maximum number of seconds to try reserving. </td></tr>
|
||||
<tr><td class="paramname">pages_reserved</td><td>If not <em>NULL</em>, it is set to the actual number of pages that were reserved. </td></tr>
|
||||
<tr><td class="paramname">numa_node</td><td>The NUMA node where the memory is reserved (start at 0). </td></tr>
|
||||
<tr><td class="paramname">timeout_msecs</td><td>Maximum number of milli-seconds to try reserving, or 0 for no timeout. </td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section return"><dt>Returns</dt><dd>0 if successfull, <em>ENOMEM</em> if running out of memory, or <em>ETIMEDOUT</em> if timed out.</dd></dl>
|
||||
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em>max_secs</em> are expired if it estimates it will take more than 1.5 times <em>max_secs</em>. 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. </p>
|
||||
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em>timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em>timeout_msecs</em>. 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. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga3132f521fb756fc0e8ec0b74fb58df50"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga3132f521fb756fc0e8ec0b74fb58df50">◆ </a></span>mi_reserve_huge_os_pages_interleave()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">int mi_reserve_huge_os_pages_interleave </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>pages</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>numa_nodes</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>timeout_msecs</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Reserve <em>pages</em> of huge OS pages (1GiB) evenly divided over <em>numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">pages</td><td>The number of 1GiB pages to reserve. </td></tr>
|
||||
<tr><td class="paramname">numa_nodes</td><td>The number of nodes do evenly divide the pages over, or 0 for using the actual number of NUMA nodes. </td></tr>
|
||||
<tr><td class="paramname">timeout_msecs</td><td>Maximum number of milli-seconds to try reserving, or 0 for no timeout. </td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="section return"><dt>Returns</dt><dd>0 if successfull, <em>ENOMEM</em> if running out of memory, or <em>ETIMEDOUT</em> if timed out.</dd></dl>
|
||||
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em>timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em>timeout_msecs</em>. 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. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -495,8 +645,8 @@ Functions</h2></td></tr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga8ca07ccff283956d71f48272f4fd5c01"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga8ca07ccff283956d71f48272f4fd5c01">◆ </a></span>mi_stats_print()</h2>
|
||||
<a id="ga2d126e5c62d3badc35445e5d84166df2"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga2d126e5c62d3badc35445e5d84166df2">◆ </a></span>mi_stats_print() <span class="overload">[1/2]</span></h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
@ -504,7 +654,7 @@ Functions</h2></td></tr>
|
||||
<tr>
|
||||
<td class="memname">void mi_stats_print </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> * </td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>out</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
@ -514,7 +664,45 @@ Functions</h2></td></tr>
|
||||
<p>Print the main statistics. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">out</td><td>Output function. Use <em>NULL</em> for outputting to <em>stderr</em>.</td></tr>
|
||||
<tr><td class="paramname">out</td><td>Ignored, outputs to the registered output function or stderr by default.</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>Most detailed when using a debug build. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga256cc6f13a142deabbadd954a217e228"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga256cc6f13a142deabbadd954a217e228">◆ </a></span>mi_stats_print() <span class="overload">[2/2]</span></h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_stats_print </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> * </td>
|
||||
<td class="paramname"><em>out</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>Print the main statistics. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">out</td><td>An output function or <em>NULL</em> for the default. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Optional argument passed to <em>out</em> (if not <em>NULL</em>)</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
@ -584,18 +772,28 @@ Functions</h2></td></tr>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga489670a15d1a257ab4639e645ee4612a"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga489670a15d1a257ab4639e645ee4612a">◆ </a></span>mi_thread_stats_print()</h2>
|
||||
<a id="gab1dac8476c46cb9eecab767eb40c1525"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gab1dac8476c46cb9eecab767eb40c1525">◆ </a></span>mi_thread_stats_print_out()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void mi_thread_stats_print </td>
|
||||
<td class="memname">void mi_thread_stats_print_out </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#ga2bed6d40b74591a67f81daea4b4a246f">mi_output_fun</a> * </td>
|
||||
<td class="paramname"><em>out</em></td><td>)</td>
|
||||
<td class="paramtype"><a class="el" href="group__extended.html#gad823d23444a4b77a40f66bf075a98a0c">mi_output_fun</a> * </td>
|
||||
<td class="paramname"><em>out</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>arg</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
@ -603,7 +801,8 @@ Functions</h2></td></tr>
|
||||
<p>Print out heap statistics for this thread. </p>
|
||||
<dl class="params"><dt>Parameters</dt><dd>
|
||||
<table class="params">
|
||||
<tr><td class="paramname">out</td><td>Output function. Use <em>NULL</em> for outputting to <em>stderr</em>.</td></tr>
|
||||
<tr><td class="paramname">out</td><td>An output function or <em>NULL</em> for the default. </td></tr>
|
||||
<tr><td class="paramname">arg</td><td>Optional argument passed to <em>out</em> (if not <em>NULL</em>)</td></tr>
|
||||
</table>
|
||||
</dd>
|
||||
</dl>
|
||||
|
@ -1,22 +1,26 @@
|
||||
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_deferred_free_fun", "group__extended.html#ga299dae78d25ce112e384a98b7309c5be", null ],
|
||||
[ "mi_error_fun", "group__extended.html#ga251d369cda3f1c2a955c555486ed90e5", null ],
|
||||
[ "mi_output_fun", "group__extended.html#gad823d23444a4b77a40f66bf075a98a0c", 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_register_output", "group__extended.html#ga84a0c8b401e42eb5b1bce156852f44c5", null ],
|
||||
[ "mi_reserve_huge_os_pages", "group__extended.html#ga2664f36a2dd557741c429cb799f04641", null ],
|
||||
[ "mi_register_deferred_free", "group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece", null ],
|
||||
[ "mi_register_error", "group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45", null ],
|
||||
[ "mi_register_output", "group__extended.html#gae5b17ff027cd2150b43a33040250cf3f", null ],
|
||||
[ "mi_reserve_huge_os_pages_at", "group__extended.html#ga7795a13d20087447281858d2c771cca1", null ],
|
||||
[ "mi_reserve_huge_os_pages_interleave", "group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50", null ],
|
||||
[ "mi_stats_merge", "group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1", null ],
|
||||
[ "mi_stats_print", "group__extended.html#ga8ca07ccff283956d71f48272f4fd5c01", null ],
|
||||
[ "mi_stats_print", "group__extended.html#ga2d126e5c62d3badc35445e5d84166df2", null ],
|
||||
[ "mi_stats_print", "group__extended.html#ga256cc6f13a142deabbadd954a217e228", 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_thread_stats_print_out", "group__extended.html#gab1dac8476c46cb9eecab767eb40c1525", null ],
|
||||
[ "mi_usable_size", "group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee", null ],
|
||||
[ "mi_zalloc_small", "group__extended.html#ga220f29f40a44404b0061c15bc1c31152", null ]
|
||||
];
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -123,11 +123,12 @@ Enumerations</h2></td></tr>
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1">mi_option_segment_cache</a>,
|
||||
<br />
|
||||
  <a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968">mi_option_page_reset</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07">mi_option_cache_reset</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536">mi_option_reset_decommits</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c">mi_option_eager_commit_delay</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d">mi_option_segment_reset</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5">mi_option_reset_delay</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74">mi_option_use_numa_nodes</a>,
|
||||
<br />
|
||||
  <a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d">mi_option_segment_reset</a>,
|
||||
  <a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536">mi_option_reset_decommits</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c">mi_option_eager_commit_delay</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf">mi_option_os_tag</a>,
|
||||
<a class="el" href="group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a">_mi_option_last</a>
|
||||
<br />
|
||||
@ -183,16 +184,18 @@ Functions</h2></td></tr>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca2ecbe7ef32f5c84de3739aa4f0b805a1"></a>mi_option_segment_cache </td><td class="fielddoc"><p>The number of segments per thread to keep cached. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968"></a>mi_option_page_reset </td><td class="fielddoc"><p>Reset page memory when it becomes free. </p>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cada854dd272c66342f18a93ee254a2968"></a>mi_option_page_reset </td><td class="fielddoc"><p>Reset page memory after <em>mi_option_reset_delay</em> milliseconds when it becomes free. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cac2157a0cb79cd996c1db7d9f6a090c07"></a>mi_option_cache_reset </td><td class="fielddoc"><p>Reset segment memory when a segment is cached. </p>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d"></a>mi_option_segment_reset </td><td class="fielddoc"><p>Experimental. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5"></a>mi_option_reset_delay </td><td class="fielddoc"><p>Delay in milli-seconds before resetting a page (100ms by default) </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74"></a>mi_option_use_numa_nodes </td><td class="fielddoc"><p>Pretend there are at most N NUMA nodes. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536"></a>mi_option_reset_decommits </td><td class="fielddoc"><p>Experimental. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c"></a>mi_option_eager_commit_delay </td><td class="fielddoc"><p>Experimental. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d"></a>mi_option_segment_reset </td><td class="fielddoc"><p>Experimental. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf"></a>mi_option_os_tag </td><td class="fielddoc"><p>OS tag to assign to mimalloc'd memory. </p>
|
||||
</td></tr>
|
||||
<tr><td class="fieldname"><a id="ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a"></a>_mi_option_last </td><td class="fielddoc"></td></tr>
|
||||
|
@ -10,10 +10,11 @@ var group__options =
|
||||
[ "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_segment_reset", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d", null ],
|
||||
[ "mi_option_reset_delay", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5", null ],
|
||||
[ "mi_option_use_numa_nodes", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74", null ],
|
||||
[ "mi_option_reset_decommits", "group__options.html#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536", 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 ]
|
||||
] ],
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -137,18 +137,6 @@ Functions</h2></td></tr>
|
||||
<tr class="separator:ga72e9d7ffb5fe94d69bc722c8506e27bc"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga0d28d5cf61e6bfbb18c63092939fe5c9"><td class="memItemLeft" align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9">mi_free_aligned</a> (void *p, size_t alignment)</td></tr>
|
||||
<tr class="separator:ga0d28d5cf61e6bfbb18c63092939fe5c9"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545">mi_new</a> (std::size_t n) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaad048a9fce3d02c5909cd05c6ec24545"><td class="mdescLeft"> </td><td class="mdescRight">raise <code>std::bad_alloc</code> exception on failure. <a href="#gaad048a9fce3d02c5909cd05c6ec24545">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaad048a9fce3d02c5909cd05c6ec24545"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3">mi_new_aligned</a> (std::size_t n, std::align_val_t alignment) noexcept(false)</td></tr>
|
||||
<tr class="memdesc:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="mdescLeft"> </td><td class="mdescRight">raise <code>std::bad_alloc</code> exception on failure. <a href="#gaef2c2bdb4f70857902d3c8903ac095f3">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaef2c2bdb4f70857902d3c8903ac095f3"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a">mi_new_nothrow</a> (size_t n)</td></tr>
|
||||
<tr class="memdesc:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="mdescLeft"> </td><td class="mdescRight">return <code>NULL</code> on failure. <a href="#gaeaded64eda71ed6b1d569d3e723abc4a">More...</a><br /></td></tr>
|
||||
<tr class="separator:gaeaded64eda71ed6b1d569d3e723abc4a"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gab5e29558926d934c3f1cae8c815f942c"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__posix.html#gab5e29558926d934c3f1cae8c815f942c">mi_new_aligned_nothrow</a> (size_t n, size_t alignment)</td></tr>
|
||||
<tr class="memdesc:gab5e29558926d934c3f1cae8c815f942c"><td class="mdescLeft"> </td><td class="mdescRight">return <code>NULL</code> on failure. <a href="#gab5e29558926d934c3f1cae8c815f942c">More...</a><br /></td></tr>
|
||||
<tr class="separator:gab5e29558926d934c3f1cae8c815f942c"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table>
|
||||
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
|
||||
<p><code>mi_</code> prefixed implementations of various Posix, Unix, and C++ allocation functions. </p>
|
||||
@ -388,122 +376,6 @@ Functions</h2></td></tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaad048a9fce3d02c5909cd05c6ec24545"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaad048a9fce3d02c5909cd05c6ec24545">◆ </a></span>mi_new()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">std::size_t </td>
|
||||
<td class="paramname"><em>n</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaef2c2bdb4f70857902d3c8903ac095f3"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaef2c2bdb4f70857902d3c8903ac095f3">◆ </a></span>mi_new_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="mlabels">
|
||||
<tr>
|
||||
<td class="mlabels-left">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">std::size_t </td>
|
||||
<td class="paramname"><em>n</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">std::align_val_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="mlabels-right">
|
||||
<span class="mlabels"><span class="mlabel">noexcept</span></span> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>raise <code>std::bad_alloc</code> exception on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gab5e29558926d934c3f1cae8c815f942c"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gab5e29558926d934c3f1cae8c815f942c">◆ </a></span>mi_new_aligned_nothrow()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_aligned_nothrow </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>n</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>return <code>NULL</code> on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gaeaded64eda71ed6b1d569d3e723abc4a"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gaeaded64eda71ed6b1d569d3e723abc4a">◆ </a></span>mi_new_nothrow()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_new_nothrow </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>n</em></td><td>)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
<p>return <code>NULL</code> on failure. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gacff84f226ba9feb2031b8992e5579447"></a>
|
||||
|
@ -9,10 +9,6 @@ var group__posix =
|
||||
[ "mi_malloc_size", "group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de", null ],
|
||||
[ "mi_malloc_usable_size", "group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17", null ],
|
||||
[ "mi_memalign", "group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e", null ],
|
||||
[ "mi_new", "group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545", null ],
|
||||
[ "mi_new_aligned", "group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3", null ],
|
||||
[ "mi_new_aligned_nothrow", "group__posix.html#gab5e29558926d934c3f1cae8c815f942c", null ],
|
||||
[ "mi_new_nothrow", "group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a", null ],
|
||||
[ "mi_posix_memalign", "group__posix.html#gacff84f226ba9feb2031b8992e5579447", null ],
|
||||
[ "mi_pvalloc", "group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e", null ],
|
||||
[ "mi_reallocarray", "group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088", null ],
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
597
docs/group__zeroinit.html
Normal file
597
docs/group__zeroinit.html
Normal file
@ -0,0 +1,597 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>mi-malloc: Zero initialized re-allocation</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="resize.js"></script>
|
||||
<script type="text/javascript" src="navtreedata.js"></script>
|
||||
<script type="text/javascript" src="navtree.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(initResizable);
|
||||
/* @license-end */</script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function() { init_search(); });
|
||||
/* @license-end */
|
||||
</script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="mimalloc-doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
<span class="left">
|
||||
<img id="MSearchSelect" src="search/mag_sel.png"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
alt=""/>
|
||||
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
||||
onfocus="searchBox.OnSearchFieldFocus(true)"
|
||||
onblur="searchBox.OnSearchFieldFocus(false)"
|
||||
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
||||
</span><span class="right">
|
||||
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.15 -->
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
/* @license-end */
|
||||
</script>
|
||||
</div><!-- top -->
|
||||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||
<div id="nav-tree">
|
||||
<div id="nav-tree-contents">
|
||||
<div id="nav-sync" class="sync"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="splitbar" style="-moz-user-select:none;"
|
||||
class="ui-resizable-handle">
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
$(document).ready(function(){initNavTree('group__zeroinit.html','');});
|
||||
/* @license-end */
|
||||
</script>
|
||||
<div id="doc-content">
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="summary">
|
||||
<a href="#func-members">Functions</a> </div>
|
||||
<div class="headertitle">
|
||||
<div class="title">Zero initialized re-allocation</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
|
||||
<p>The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too.
|
||||
<a href="#details">More...</a></p>
|
||||
<table class="memberdecls">
|
||||
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
|
||||
Functions</h2></td></tr>
|
||||
<tr class="memitem:ga8c292e142110229a2980b37ab036dbc6"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6">mi_rezalloc</a> (void *p, size_t newsize)</td></tr>
|
||||
<tr class="separator:ga8c292e142110229a2980b37ab036dbc6"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gacd71a7bce96aab38ae6de17af2eb2cf0"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0">mi_rezalloc_aligned</a> (void *p, size_t newsize, size_t alignment)</td></tr>
|
||||
<tr class="separator:gacd71a7bce96aab38ae6de17af2eb2cf0"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gae8b358c417e61d5307da002702b0a8e1"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1">mi_rezalloc_aligned_at</a> (void *p, size_t newsize, size_t alignment, size_t offset)</td></tr>
|
||||
<tr class="separator:gae8b358c417e61d5307da002702b0a8e1"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga3e7e5c291acf1c7fd7ffd9914a9f945f"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f">mi_recalloc_aligned</a> (void *p, size_t newcount, size_t size, size_t alignment)</td></tr>
|
||||
<tr class="separator:ga3e7e5c291acf1c7fd7ffd9914a9f945f"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga4ff5e92ad73585418a072c9d059e5cf9"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9">mi_recalloc_aligned_at</a> (void *p, size_t newcount, size_t size, size_t alignment, size_t offset)</td></tr>
|
||||
<tr class="separator:ga4ff5e92ad73585418a072c9d059e5cf9"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gacfad83f14eb5d6a42a497a898e19fc76"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76">mi_heap_rezalloc</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newsize)</td></tr>
|
||||
<tr class="separator:gacfad83f14eb5d6a42a497a898e19fc76"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga8648c5fbb22a80f0262859099f06dfbd"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd">mi_heap_recalloc</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newcount, size_t size)</td></tr>
|
||||
<tr class="separator:ga8648c5fbb22a80f0262859099f06dfbd"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga375fa8a611c51905e592d5d467c49664"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664">mi_heap_rezalloc_aligned</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newsize, size_t alignment)</td></tr>
|
||||
<tr class="separator:ga375fa8a611c51905e592d5d467c49664"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:gac90da54fa7e5d10bdc97ce0b51dce2eb"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb">mi_heap_rezalloc_aligned_at</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newsize, size_t alignment, size_t offset)</td></tr>
|
||||
<tr class="separator:gac90da54fa7e5d10bdc97ce0b51dce2eb"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga9f3f999396c8f77ca5e80e7b40ac29e3"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3">mi_heap_recalloc_aligned</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newcount, size_t size, size_t alignment)</td></tr>
|
||||
<tr class="separator:ga9f3f999396c8f77ca5e80e7b40ac29e3"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
<tr class="memitem:ga496452c96f1de8c500be9fddf52edaf7"><td class="memItemLeft" align="right" valign="top">void * </td><td class="memItemRight" valign="bottom"><a class="el" href="group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7">mi_heap_recalloc_aligned_at</a> (<a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)</td></tr>
|
||||
<tr class="separator:ga496452c96f1de8c500be9fddf52edaf7"><td class="memSeparator" colspan="2"> </td></tr>
|
||||
</table>
|
||||
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
|
||||
<p>The zero-initialized re-allocations are only valid on memory that was originally allocated with zero initialization too. </p>
|
||||
<p>e.g. <code>mi_calloc</code>, <code>mi_zalloc</code>, <code>mi_zalloc_aligned</code> etc. see <a href="https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992">https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992</a> </p>
|
||||
<h2 class="groupheader">Function Documentation</h2>
|
||||
<a id="ga8648c5fbb22a80f0262859099f06dfbd"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga8648c5fbb22a80f0262859099f06dfbd">◆ </a></span>mi_heap_recalloc()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_recalloc </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga9f3f999396c8f77ca5e80e7b40ac29e3"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga9f3f999396c8f77ca5e80e7b40ac29e3">◆ </a></span>mi_heap_recalloc_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_recalloc_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga496452c96f1de8c500be9fddf52edaf7"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga496452c96f1de8c500be9fddf52edaf7">◆ </a></span>mi_heap_recalloc_aligned_at()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_recalloc_aligned_at </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>offset</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gacfad83f14eb5d6a42a497a898e19fc76"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gacfad83f14eb5d6a42a497a898e19fc76">◆ </a></span>mi_heap_rezalloc()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_rezalloc </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga375fa8a611c51905e592d5d467c49664"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga375fa8a611c51905e592d5d467c49664">◆ </a></span>mi_heap_rezalloc_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_rezalloc_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gac90da54fa7e5d10bdc97ce0b51dce2eb"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gac90da54fa7e5d10bdc97ce0b51dce2eb">◆ </a></span>mi_heap_rezalloc_aligned_at()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_heap_rezalloc_aligned_at </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype"><a class="el" href="group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2">mi_heap_t</a> * </td>
|
||||
<td class="paramname"><em>heap</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>offset</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga3e7e5c291acf1c7fd7ffd9914a9f945f"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga3e7e5c291acf1c7fd7ffd9914a9f945f">◆ </a></span>mi_recalloc_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_recalloc_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga4ff5e92ad73585418a072c9d059e5cf9"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga4ff5e92ad73585418a072c9d059e5cf9">◆ </a></span>mi_recalloc_aligned_at()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_recalloc_aligned_at </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newcount</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>size</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>offset</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="ga8c292e142110229a2980b37ab036dbc6"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#ga8c292e142110229a2980b37ab036dbc6">◆ </a></span>mi_rezalloc()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_rezalloc </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gacd71a7bce96aab38ae6de17af2eb2cf0"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gacd71a7bce96aab38ae6de17af2eb2cf0">◆ </a></span>mi_rezalloc_aligned()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_rezalloc_aligned </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a id="gae8b358c417e61d5307da002702b0a8e1"></a>
|
||||
<h2 class="memtitle"><span class="permalink"><a href="#gae8b358c417e61d5307da002702b0a8e1">◆ </a></span>mi_rezalloc_aligned_at()</h2>
|
||||
|
||||
<div class="memitem">
|
||||
<div class="memproto">
|
||||
<table class="memname">
|
||||
<tr>
|
||||
<td class="memname">void* mi_rezalloc_aligned_at </td>
|
||||
<td>(</td>
|
||||
<td class="paramtype">void * </td>
|
||||
<td class="paramname"><em>p</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>newsize</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>alignment</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="paramkey"></td>
|
||||
<td></td>
|
||||
<td class="paramtype">size_t </td>
|
||||
<td class="paramname"><em>offset</em> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>)</td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div><div class="memdoc">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- contents -->
|
||||
</div><!-- doc-content -->
|
||||
<!-- start footer part -->
|
||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||
<ul>
|
||||
<li class="footer">Generated by
|
||||
<a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.15 </li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
docs/group__zeroinit.js
Normal file
14
docs/group__zeroinit.js
Normal file
@ -0,0 +1,14 @@
|
||||
var group__zeroinit =
|
||||
[
|
||||
[ "mi_heap_recalloc", "group__zeroinit.html#ga8648c5fbb22a80f0262859099f06dfbd", null ],
|
||||
[ "mi_heap_recalloc_aligned", "group__zeroinit.html#ga9f3f999396c8f77ca5e80e7b40ac29e3", null ],
|
||||
[ "mi_heap_recalloc_aligned_at", "group__zeroinit.html#ga496452c96f1de8c500be9fddf52edaf7", null ],
|
||||
[ "mi_heap_rezalloc", "group__zeroinit.html#gacfad83f14eb5d6a42a497a898e19fc76", null ],
|
||||
[ "mi_heap_rezalloc_aligned", "group__zeroinit.html#ga375fa8a611c51905e592d5d467c49664", null ],
|
||||
[ "mi_heap_rezalloc_aligned_at", "group__zeroinit.html#gac90da54fa7e5d10bdc97ce0b51dce2eb", null ],
|
||||
[ "mi_recalloc_aligned", "group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f", null ],
|
||||
[ "mi_recalloc_aligned_at", "group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9", null ],
|
||||
[ "mi_rezalloc", "group__zeroinit.html#ga8c292e142110229a2980b37ab036dbc6", null ],
|
||||
[ "mi_rezalloc_aligned", "group__zeroinit.html#gacd71a7bce96aab38ae6de17af2eb2cf0", null ],
|
||||
[ "mi_rezalloc_aligned_at", "group__zeroinit.html#gae8b358c417e61d5307da002702b0a8e1", null ]
|
||||
];
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -105,7 +105,7 @@ $(document).ready(function(){initNavTree('index.html','');});
|
||||
<div class="textblock"><p>This is the API documentation of the <a href="https://github.com/microsoft/mimalloc">mimalloc</a> allocator (pronounced "me-malloc") – a general purpose allocator with excellent <a href="bench.html">performance</a> characteristics. Initially developed by Daan Leijen for the run-time systems of the <a href="https://github.com/koka-lang/koka">Koka</a> and <a href="https://github.com/leanprover/lean">Lean</a> languages.</p>
|
||||
<p>It is a drop-in replacement for <code>malloc</code> and can be used in other programs without code changes, for example, on Unix you can use it as: </p><div class="fragment"><div class="line">> LD_PRELOAD=/usr/bin/libmimalloc.so myprogram</div></div><!-- fragment --><p>Notable aspects of the design include:</p>
|
||||
<ul>
|
||||
<li><b>small and consistent</b>: the library is less than 3500 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 <em>heartbeat</em> and deferred freeing (for bounded worst-case times with reference counting).</li>
|
||||
<li><b>small and consistent</b>: the library is less than 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 <em>heartbeat</em> and deferred freeing (for bounded worst-case times with reference counting).</li>
|
||||
<li><b>free list sharding</b>: the big idea: instead of one big free list (per size class) we have many smaller lists per memory "page" which both reduces fragmentation and increases locality – things that are allocated close in time get allocated close in memory. (A memory "page" in <em>mimalloc</em> contains blocks of one size class and is usually 64KiB on a 64-bit system).</li>
|
||||
<li><b>eager page reset</b>: 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.</li>
|
||||
<li><b>secure</b>: <em>mimalloc</em> 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.</li>
|
||||
|
File diff suppressed because one or more lines are too long
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -113,6 +113,7 @@ $(document).ready(function(){initNavTree('modules.html','');});
|
||||
<tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="group__analysis.html" target="_self">Heap Introspection</a></td><td class="desc">Inspect the heap at runtime </td></tr>
|
||||
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="group__options.html" target="_self">Runtime Options</a></td><td class="desc">Set runtime behavior </td></tr>
|
||||
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="group__posix.html" target="_self">Posix</a></td><td class="desc"><code>mi_</code> prefixed implementations of various Posix, Unix, and C++ allocation functions </td></tr>
|
||||
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="group__cpp.html" target="_self">C++ wrappers</a></td><td class="desc"><code>mi_</code> prefixed implementations of various allocation functions that use C++ semantics on out-of-memory, generally calling <code>std::get_new_handler</code> and raising a <code>std::bad_alloc</code> exception on failure </td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
|
@ -8,5 +8,6 @@ var modules =
|
||||
[ "Typed Macros", "group__typed.html", "group__typed" ],
|
||||
[ "Heap Introspection", "group__analysis.html", "group__analysis" ],
|
||||
[ "Runtime Options", "group__options.html", "group__options" ],
|
||||
[ "Posix", "group__posix.html", "group__posix" ]
|
||||
[ "Posix", "group__posix.html", "group__posix" ],
|
||||
[ "C++ wrappers", "group__cpp.html", "group__cpp" ]
|
||||
];
|
@ -28,26 +28,39 @@ var NAVTREEINDEX0 =
|
||||
"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__cpp.html":[5,9],
|
||||
"group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907":[5,9,7],
|
||||
"group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e":[5,9,6],
|
||||
"group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545":[5,9,1],
|
||||
"group__cpp.html#gab5e29558926d934c3f1cae8c815f942c":[5,9,3],
|
||||
"group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81":[5,9,4],
|
||||
"group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,9,5],
|
||||
"group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3":[5,9,2],
|
||||
"group__cpp.html#structmi__stl__allocator":[5,9,0],
|
||||
"group__extended.html":[5,1],
|
||||
"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,17],
|
||||
"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,14],
|
||||
"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,21],
|
||||
"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,18],
|
||||
"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__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,22],
|
||||
"group__extended.html#ga251d369cda3f1c2a955c555486ed90e5":[5,1,2],
|
||||
"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,16],
|
||||
"group__extended.html#ga299dae78d25ce112e384a98b7309c5be":[5,1,1],
|
||||
"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,15],
|
||||
"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,13],
|
||||
"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,9],
|
||||
"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,17],
|
||||
"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,4],
|
||||
"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6],
|
||||
"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8],
|
||||
"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,12],
|
||||
"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,14],
|
||||
"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,10],
|
||||
"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,7],
|
||||
"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,20],
|
||||
"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,5],
|
||||
"group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,3],
|
||||
"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,11],
|
||||
"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,19],
|
||||
"group__heap.html":[5,3],
|
||||
"group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[5,3,20],
|
||||
"group__heap.html#ga08ca6419a5c057a4d965868998eef487":[5,3,3],
|
||||
@ -99,38 +112,35 @@ var NAVTREEINDEX0 =
|
||||
"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#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74":[5,7,0,11],
|
||||
"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5":[5,7,0,10],
|
||||
"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c":[5,7,0,13],
|
||||
"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#ggafebf7ed116adb38ae5218bc3ce06884ca4b74ae2a69e445de6c2361b73c1d14bf":[5,7,0,14],
|
||||
"group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca5b4357b74be0d87568036c32eb1a2e4a":[5,7,0,15],
|
||||
"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#ggafebf7ed116adb38ae5218bc3ce06884cac81ee965b130fa81238913a3c239d536":[5,7,0,12],
|
||||
"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#ggafebf7ed116adb38ae5218bc3ce06884cafb121d30d87591850d5410ccc3a95c6d":[5,7,0,9],
|
||||
"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#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,11],
|
||||
"group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7":[5,8,2],
|
||||
"group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc":[5,8,5],
|
||||
"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,16],
|
||||
"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,12],
|
||||
"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#gacff84f226ba9feb2031b8992e5579447":[5,8,9],
|
||||
"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__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,10],
|
||||
"group__typed.html":[5,5],
|
||||
"group__typed.html#ga0619a62c5fd886f1016030abe91f0557":[5,5,7],
|
||||
"group__typed.html#ga1158b49a55dfa81f58a4426a7578f523":[5,5,9],
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -118,10 +118,10 @@ $(document).ready(function(){initNavTree('overrides.html','');});
|
||||
<p>Note that certain security restrictions may apply when doing this from the <a href="https://stackoverflow.com/questions/43941322/dyld-insert-libraries-ignored-when-calling-application-through-bash">shell</a>.</p>
|
||||
<p>Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is actively worked on to fix this (see issue <a href="https://github.com/microsoft/mimalloc/issues/50"><code>#50</code></a>).</p>
|
||||
<h3>Windows</h3>
|
||||
<p>On Windows you need to link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the <code>/MD</code> or <code>/MDd</code> switch). Moreover, you need to ensure the <code>mimalloc-redirect.dll</code> (or <code>mimalloc-redirect32.dll</code>) 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.</p>
|
||||
<p>To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the <code>main</code> function, like <code>mi_version()</code> (or use the <code>/INCLUDE:mi_version</code> switch on the linker). See the <code>mimalloc-override-test</code> project for an example on how to use this.</p>
|
||||
<p>The environment variable <code>MIMALLOC_DISABLE_REDIRECT=1</code> can be used to disable dynamic overriding at run-time. Use <code>MIMALLOC_VERBOSE=1</code> to check if mimalloc successfully redirected.</p>
|
||||
<p>(Note: in principle, it should be possible to patch existing executables that are linked with the dynamic C runtime (<code>ucrtbase.dll</code>) by just putting the mimalloc DLL into the import table (and putting <code>mimalloc-redirect.dll</code> in the same folder) Such patching can be done for example with <a href="https://ntcore.com/?page_id=388">CFF Explorer</a>).</p>
|
||||
<p>Overriding on Windows is robust but requires that you link your program explicitly with the mimalloc DLL and use the C-runtime library as a DLL (using the <code>/MD</code> or <code>/MDd</code> switch). Moreover, you need to ensure the <code>mimalloc-redirect.dll</code> (or <code>mimalloc-redirect32.dll</code>) is available in the same folder as the main <code>mimalloc-override.dll</code> at runtime (as it is a dependency). The redirection DLL ensures that all calls to the C runtime malloc API get redirected to mimalloc (in <code>mimalloc-override.dll</code>).</p>
|
||||
<p>To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some call to the mimalloc API in the <code>main</code> function, like <code>mi_version()</code> (or use the <code>/INCLUDE:mi_version</code> switch on the linker). See the <code>mimalloc-override-test</code> project for an example on how to use this. For best performance on Windows with C++, it is highly recommended to also override the <code>new</code>/<code>delete</code> operations (by including <a href="https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h"><code>mimalloc-new-delete.h</code></a> a single(!) source file in your project).</p>
|
||||
<p>The environment variable <code>MIMALLOC_DISABLE_REDIRECT=1</code> can be used to disable dynamic overriding at run-time. Use <code>MIMALLOC_VERBOSE=1</code> to check if mimalloc was successfully redirected.</p>
|
||||
<p>(Note: in principle, it is possible to patch existing executables that are linked with the dynamic C runtime (<code>ucrtbase.dll</code>) by just putting the <code>mimalloc-override.dll</code> into the import table (and putting <code>mimalloc-redirect.dll</code> in the same folder) Such patching can be done for example with <a href="https://ntcore.com/?page_id=388">CFF Explorer</a>).</p>
|
||||
<h2>Static override</h2>
|
||||
<p>On Unix systems, you can also statically link with <em>mimalloc</em> to override the standard malloc interface. The recommended way is to link the final program with the <em>mimalloc</em> single object file (<code>mimalloc-override.o</code>). 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 <em>mimalloc</em> library, link it as the first object file. For example:</p>
|
||||
<div class="fragment"><div class="line">gcc -o myprogram mimalloc-<span class="keyword">override</span>.o myfile1.c ...</div></div><!-- fragment --><h2>List of Overrides:</h2>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
|
@ -1,4 +1,5 @@
|
||||
var searchData=
|
||||
[
|
||||
['committed',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]]
|
||||
['committed',['committed',['../group__analysis.html#ab47526df656d8837ec3e97f11b83f835',1,'mi_heap_area_t']]],
|
||||
['c_2b_2b_20wrappers',['C++ wrappers',['../group__cpp.html',1,'']]]
|
||||
];
|
||||
|
@ -10,7 +10,8 @@ var searchData=
|
||||
['mi_5fcfree',['mi_cfree',['../group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7',1,'mimalloc-doc.h']]],
|
||||
['mi_5fcheck_5fowned',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]],
|
||||
['mi_5fcollect',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]],
|
||||
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga22213691c3ce5ab4d91b24aff1023529',1,'mimalloc-doc.h']]],
|
||||
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
|
||||
['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]],
|
||||
['mi_5fexpand',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]],
|
||||
['mi_5ffree',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]],
|
||||
['mi_5ffree_5faligned',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]],
|
||||
@ -72,11 +73,13 @@ var searchData=
|
||||
['mi_5fmallocn',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]],
|
||||
['mi_5fmallocn_5ftp',['mi_mallocn_tp',['../group__typed.html#gae5cb6e0fafc9f23169c5622e077afe8b',1,'mimalloc-doc.h']]],
|
||||
['mi_5fmemalign',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['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_5fnew',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fn',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5frealloc',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5freallocn',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',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']]],
|
||||
@ -89,6 +92,7 @@ var searchData=
|
||||
['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_5fdelay',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',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']]],
|
||||
@ -96,8 +100,9 @@ var searchData=
|
||||
['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_5fuse_5fnuma_5fnodes',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',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_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',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']]],
|
||||
@ -111,21 +116,24 @@ var searchData=
|
||||
['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_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',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_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_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mi_stats_print(void *out): mimalloc-doc.h'],['../group__extended.html#ga256cc6f13a142deabbadd954a217e228',1,'mi_stats_print(mi_output_fun *out, void *arg): mimalloc-doc.h']]],
|
||||
['mi_5fstats_5freset',['mi_stats_reset',['../group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99',1,'mimalloc-doc.h']]],
|
||||
['mi_5fstl_5fallocator',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]],
|
||||
['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#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_5fthread_5fstats_5fprint_5fout',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',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']]],
|
||||
|
30
docs/search/all_c.html
Normal file
30
docs/search/all_c.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_c.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/all_c.js
Normal file
4
docs/search/all_c.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['zero_20initialized_20re_2dallocation',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]]
|
||||
];
|
30
docs/search/all_d.html
Normal file
30
docs/search/all_d.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_d.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/all_d.js
Normal file
4
docs/search/all_d.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['zero_20initialized_20re_2dallocation',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]]
|
||||
];
|
@ -1,4 +1,5 @@
|
||||
var searchData=
|
||||
[
|
||||
['mi_5fheap_5farea_5ft',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]]
|
||||
['mi_5fheap_5farea_5ft',['mi_heap_area_t',['../group__analysis.html#structmi__heap__area__t',1,'']]],
|
||||
['mi_5fstl_5fallocator',['mi_stl_allocator',['../group__cpp.html#structmi__stl__allocator',1,'']]]
|
||||
];
|
||||
|
@ -1,6 +1,5 @@
|
||||
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']]],
|
||||
@ -9,9 +8,11 @@ var searchData=
|
||||
['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_5fdelay',['mi_option_reset_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca154fe170131d5212cff57e22b99523c5',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_5fuse_5fnuma_5fnodes',['mi_option_use_numa_nodes',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca0ac33a18f6b659fcfaf44efb0bab1b74',1,'mimalloc-doc.h']]],
|
||||
['mi_5foption_5fverbose',['mi_option_verbose',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca7c8b7bf5281c581bad64f5daa6442777',1,'mimalloc-doc.h']]]
|
||||
];
|
||||
|
@ -59,10 +59,13 @@ var searchData=
|
||||
['mi_5fmalloc_5fusable_5fsize',['mi_malloc_usable_size',['../group__posix.html#ga06d07cf357bbac5c73ba5d0c0c421e17',1,'mimalloc-doc.h']]],
|
||||
['mi_5fmallocn',['mi_mallocn',['../group__malloc.html#ga0b05e2bf0f73e7401ae08597ff782ac6',1,'mimalloc-doc.h']]],
|
||||
['mi_5fmemalign',['mi_memalign',['../group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew',['mi_new',['../group__cpp.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned',['mi_new_aligned',['../group__cpp.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__cpp.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fn',['mi_new_n',['../group__cpp.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__cpp.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5frealloc',['mi_new_realloc',['../group__cpp.html#gaab78a32f55149e9fbf432d5288e38e1e',1,'mimalloc-doc.h']]],
|
||||
['mi_5fnew_5freallocn',['mi_new_reallocn',['../group__cpp.html#ga756f4b2bc6a7ecd0a90baea8e90c7907',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']]],
|
||||
@ -81,20 +84,22 @@ var searchData=
|
||||
['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_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
|
||||
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
|
||||
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',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_5fprint',['mi_stats_print',['../group__extended.html#ga2d126e5c62d3badc35445e5d84166df2',1,'mi_stats_print(void *out): mimalloc-doc.h'],['../group__extended.html#ga256cc6f13a142deabbadd954a217e228',1,'mi_stats_print(mi_output_fun *out, void *arg): 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#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_5fthread_5fstats_5fprint_5fout',['mi_thread_stats_print_out',['../group__extended.html#gab1dac8476c46cb9eecab767eb40c1525',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']]],
|
||||
|
30
docs/search/functions_1.html
Normal file
30
docs/search/functions_1.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="functions_1.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/functions_1.js
Normal file
4
docs/search/functions_1.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['void',['void',['../group__extended.html#gadc49452cc1634aa03ac83ffe9b97a19c',1,'mimalloc-doc.h']]]
|
||||
];
|
@ -1,4 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['extended_20functions',['Extended Functions',['../group__extended.html',1,'']]]
|
||||
['c_2b_2b_20wrappers',['C++ wrappers',['../group__cpp.html',1,'']]]
|
||||
];
|
||||
|
@ -1,5 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['heap_20introspection',['Heap Introspection',['../group__analysis.html',1,'']]],
|
||||
['heap_20allocation',['Heap Allocation',['../group__heap.html',1,'']]]
|
||||
['extended_20functions',['Extended Functions',['../group__extended.html',1,'']]]
|
||||
];
|
||||
|
@ -1,4 +1,5 @@
|
||||
var searchData=
|
||||
[
|
||||
['posix',['Posix',['../group__posix.html',1,'']]]
|
||||
['heap_20introspection',['Heap Introspection',['../group__analysis.html',1,'']]],
|
||||
['heap_20allocation',['Heap Allocation',['../group__heap.html',1,'']]]
|
||||
];
|
||||
|
@ -1,4 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['runtime_20options',['Runtime Options',['../group__options.html',1,'']]]
|
||||
['posix',['Posix',['../group__posix.html',1,'']]]
|
||||
];
|
||||
|
@ -1,4 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['typed_20macros',['Typed Macros',['../group__typed.html',1,'']]]
|
||||
['runtime_20options',['Runtime Options',['../group__options.html',1,'']]]
|
||||
];
|
||||
|
30
docs/search/groups_7.html
Normal file
30
docs/search/groups_7.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="groups_7.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/groups_7.js
Normal file
4
docs/search/groups_7.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['typed_20macros',['Typed Macros',['../group__typed.html',1,'']]]
|
||||
];
|
30
docs/search/groups_8.html
Normal file
30
docs/search/groups_8.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="groups_8.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/groups_8.js
Normal file
4
docs/search/groups_8.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['zero_20initialized_20re_2dallocation',['Zero initialized re-allocation',['../group__zeroinit.html',1,'']]]
|
||||
];
|
30
docs/search/pages_4.html
Normal file
30
docs/search/pages_4.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="pages_4.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/pages_4.js
Normal file
4
docs/search/pages_4.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['using_20the_20library',['Using the library',['../using.html',1,'']]]
|
||||
];
|
@ -7,7 +7,7 @@ var indexSectionsWithContent =
|
||||
4: "m",
|
||||
5: "m",
|
||||
6: "_m",
|
||||
7: "abehprtz",
|
||||
7: "abcehprtz",
|
||||
8: "beopu"
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
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_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
|
||||
['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',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']]]
|
||||
['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]]
|
||||
];
|
||||
|
30
docs/search/typedefs_1.html
Normal file
30
docs/search/typedefs_1.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="typedefs_1.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
4
docs/search/typedefs_1.js
Normal file
4
docs/search/typedefs_1.js
Normal file
@ -0,0 +1,4 @@
|
||||
var searchData=
|
||||
[
|
||||
['heartbeat',['heartbeat',['../group__extended.html#ga411f6e94394a2400aa460c796beff8d8',1,'mimalloc-doc.h']]]
|
||||
];
|
30
docs/search/typedefs_2.html
Normal file
30
docs/search/typedefs_2.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.15"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="typedefs_2.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
createResults();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
/* @license-end */
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
5
docs/search/typedefs_2.js
Normal file
5
docs/search/typedefs_2.js
Normal file
@ -0,0 +1,5 @@
|
||||
var searchData=
|
||||
[
|
||||
['mi_5fblock_5fvisit_5ffun',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]],
|
||||
['mi_5fheap_5ft',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]]
|
||||
];
|
@ -37,7 +37,7 @@
|
||||
<td id="projectlogo"><img alt="Logo" src="mimalloc-logo.svg"/></td>
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">mi-malloc
|
||||
 <span id="projectnumber">1.0</span>
|
||||
 <span id="projectnumber">1.4</span>
|
||||
</div>
|
||||
</td>
|
||||
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||||
@ -102,7 +102,11 @@ $(document).ready(function(){initNavTree('using.html','');});
|
||||
<div class="title">Using the library </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>The preferred usage is including <code><mimalloc.h></code>, linking with the shared- or static library, and using the <code>mi_malloc</code> API exclusively for allocation. For example, </p><div class="fragment"><div class="line">gcc -o myprogram -lmimalloc myfile.c</div></div><!-- fragment --><p>mimalloc uses only safe OS calls (<code>mmap</code> and <code>VirtualAlloc</code>) and can co-exist with other allocators linked to the same program. If you use <code>cmake</code>, you can simply use: </p><div class="fragment"><div class="line">find_package(mimalloc 1.0 REQUIRED)</div></div><!-- fragment --><p> in your <code>CMakeLists.txt</code> to find a locally installed mimalloc. Then use either: </p><div class="fragment"><div class="line">target_link_libraries(myapp PUBLIC mimalloc)</div></div><!-- fragment --><p> to link with the shared (dynamic) library, or: </p><div class="fragment"><div class="line">target_link_libraries(myapp PUBLIC mimalloc-<span class="keyword">static</span>)</div></div><!-- fragment --><p> to link with the static library. See <code>test\CMakeLists.txt</code> for an example.</p>
|
||||
<div class="textblock"><h3>Build</h3>
|
||||
<p>The preferred usage is including <code><mimalloc.h></code>, linking with the shared- or static library, and using the <code>mi_malloc</code> API exclusively for allocation. For example, </p><div class="fragment"><div class="line">gcc -o myprogram -lmimalloc myfile.c</div></div><!-- fragment --><p>mimalloc uses only safe OS calls (<code>mmap</code> and <code>VirtualAlloc</code>) and can co-exist with other allocators linked to the same program. If you use <code>cmake</code>, you can simply use: </p><div class="fragment"><div class="line">find_package(mimalloc 1.0 REQUIRED)</div></div><!-- fragment --><p> in your <code>CMakeLists.txt</code> to find a locally installed mimalloc. Then use either: </p><div class="fragment"><div class="line">target_link_libraries(myapp PUBLIC mimalloc)</div></div><!-- fragment --><p> to link with the shared (dynamic) library, or: </p><div class="fragment"><div class="line">target_link_libraries(myapp PUBLIC mimalloc-<span class="keyword">static</span>)</div></div><!-- fragment --><p> to link with the static library. See <code>test\CMakeLists.txt</code> for an example.</p>
|
||||
<h3>C++</h3>
|
||||
<p>For best performance in C++ programs, it is also recommended to override the global <code>new</code> and <code>delete</code> operators. For convience, mimalloc provides <a href="https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h"><code>mimalloc-new-delete.h</code></a> which does this for you – just include it in a single(!) source file in your project.</p>
|
||||
<p>In C++, mimalloc also provides the <code><a class="el" href="group__cpp.html#structmi__stl__allocator" title="std::allocator implementation for mimalloc for use in STL containers.">mi_stl_allocator</a></code> struct which implements the <code>std::allocator</code> interface. For example: </p><div class="fragment"><div class="line">std::vector<some_struct, mi_stl_allocator<some_struct>> vec;</div><div class="line">vec.push_back(some_struct());</div></div><!-- fragment --><h3>Statistics</h3>
|
||||
<p>You can pass environment variables to print verbose messages (<code>MIMALLOC_VERBOSE=1</code>) and statistics (<code>MIMALLOC_SHOW_STATS=1</code>) (in the debug version): </p><div class="fragment"><div class="line">> env MIMALLOC_SHOW_STATS=1 ./cfrac 175451865205073170563711388363</div><div class="line"></div><div class="line">175451865205073170563711388363 = 374456281610909315237213 * 468551</div><div class="line"></div><div class="line">heap stats: peak total freed unit</div><div class="line">normal 2: 16.4 kb 17.5 mb 17.5 mb 16 b ok</div><div class="line">normal 3: 16.3 kb 15.2 mb 15.2 mb 24 b ok</div><div class="line">normal 4: 64 b 4.6 kb 4.6 kb 32 b ok</div><div class="line">normal 5: 80 b 118.4 kb 118.4 kb 40 b ok</div><div class="line">normal 6: 48 b 48 b 48 b 48 b ok</div><div class="line">normal 17: 960 b 960 b 960 b 320 b ok</div><div class="line"></div><div class="line">heap stats: peak total freed unit</div><div class="line"> normal: 33.9 kb 32.8 mb 32.8 mb 1 b ok</div><div class="line"> huge: 0 b 0 b 0 b 1 b ok</div><div class="line"> total: 33.9 kb 32.8 mb 32.8 mb 1 b ok</div><div class="line">malloc requested: 32.8 mb</div><div class="line"></div><div class="line"> committed: 58.2 kb 58.2 kb 58.2 kb 1 b ok</div><div class="line"> reserved: 2.0 mb 2.0 mb 2.0 mb 1 b ok</div><div class="line"> reset: 0 b 0 b 0 b 1 b ok</div><div class="line"> segments: 1 1 1</div><div class="line">-abandoned: 0</div><div class="line"> pages: 6 6 6</div><div class="line">-abandoned: 0</div><div class="line"> mmaps: 3</div><div class="line"> mmap fast: 0</div><div class="line"> mmap slow: 1</div><div class="line"> threads: 0</div><div class="line"> elapsed: 2.022s</div><div class="line"> process: user: 1.781s, system: 0.016s, faults: 756, reclaims: 0, rss: 2.7 mb</div></div><!-- fragment --><p>The above model of using the <code>mi_</code> 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 <em>mimalloc</em> library instead.</p>
|
||||
<p>See <a class="el" href="overrides.html">Overriding Malloc</a> for more info. </p>
|
||||
</div></div><!-- PageDoc -->
|
||||
|
@ -112,7 +112,7 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -129,7 +129,7 @@
|
||||
<CompileAs>Default</CompileAs>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
<ModuleDefinitionFile>
|
||||
@ -195,7 +195,7 @@
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>$(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(ProjectDir)\..\..\bin\mimalloc-redirect.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
@ -231,9 +231,10 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\heap.c" />
|
||||
<ClCompile Include="..\..\src\init.c" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\region.c" />
|
||||
<ClCompile Include="..\..\src\options.c" />
|
||||
<ClCompile Include="..\..\src\os.c" />
|
||||
<ClCompile Include="..\..\src\page-queue.c">
|
||||
@ -243,10 +244,11 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\page.c" />
|
||||
<ClCompile Include="..\..\src\random.c" />
|
||||
<ClCompile Include="..\..\src\segment.c" />
|
||||
<ClCompile Include="..\..\src\stats.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -61,7 +61,7 @@
|
||||
<ClCompile Include="..\..\src\init.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\memory.c">
|
||||
<ClCompile Include="..\..\src\region.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-override.c">
|
||||
@ -70,5 +70,11 @@
|
||||
<ClCompile Include="..\..\src\alloc-posix.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\random.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -111,7 +111,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
@ -165,7 +165,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
@ -217,9 +217,10 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\heap.c" />
|
||||
<ClCompile Include="..\..\src\init.c" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\region.c" />
|
||||
<ClCompile Include="..\..\src\options.c" />
|
||||
<ClCompile Include="..\..\src\page-queue.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@ -228,6 +229,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\page.c" />
|
||||
<ClCompile Include="..\..\src\random.c" />
|
||||
<ClCompile Include="..\..\src\segment.c" />
|
||||
<ClCompile Include="..\..\src\os.c" />
|
||||
<ClCompile Include="..\..\src\stats.c" />
|
||||
@ -243,4 +245,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -47,12 +47,18 @@
|
||||
<ClCompile Include="..\..\src\init.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\memory.c">
|
||||
<ClCompile Include="..\..\src\region.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\random.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||
@ -74,4 +80,4 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -90,7 +90,7 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
@ -112,7 +112,7 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -123,7 +123,7 @@
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MI_DEBUG=3;MI_SHARED_LIB;MI_SHARED_LIB_EXPORT;MI_MALLOC_OVERRIDE;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<CompileAs>Default</CompileAs>
|
||||
@ -231,9 +231,13 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\heap.c" />
|
||||
<ClCompile Include="..\..\src\init.c" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\region.c" />
|
||||
<ClCompile Include="..\..\src\options.c" />
|
||||
<ClCompile Include="..\..\src\os.c" />
|
||||
<ClCompile Include="..\..\src\page-queue.c">
|
||||
@ -243,10 +247,11 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\page.c" />
|
||||
<ClCompile Include="..\..\src\random.c" />
|
||||
<ClCompile Include="..\..\src\segment.c" />
|
||||
<ClCompile Include="..\..\src\stats.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<ClCompile Include="..\..\src\init.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\memory.c">
|
||||
<ClCompile Include="..\..\src\region.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\os.c">
|
||||
@ -40,6 +40,15 @@
|
||||
<ClCompile Include="..\..\src\stats.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\random.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||
@ -69,4 +78,4 @@
|
||||
<UniqueIdentifier>{39cb7e38-69d0-43fb-8406-6a0f7cefc3b4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -100,7 +100,7 @@
|
||||
<PreprocessorDefinitions>MI_DEBUG=3;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>Default</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories>
|
||||
@ -111,15 +111,15 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level2</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>MI_DEBUG=1;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>MI_DEBUG=3;%(PreprocessorDefinitions);</PreprocessorDefinitions>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>Default</LanguageStandard>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
@ -217,9 +217,13 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\heap.c" />
|
||||
<ClCompile Include="..\..\src\init.c" />
|
||||
<ClCompile Include="..\..\src\memory.c" />
|
||||
<ClCompile Include="..\..\src\region.c" />
|
||||
<ClCompile Include="..\..\src\options.c" />
|
||||
<ClCompile Include="..\..\src\page-queue.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@ -228,6 +232,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\page.c" />
|
||||
<ClCompile Include="..\..\src\random.c" />
|
||||
<ClCompile Include="..\..\src\segment.c" />
|
||||
<ClCompile Include="..\..\src\os.c" />
|
||||
<ClCompile Include="..\..\src\stats.c" />
|
||||
@ -243,4 +248,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<ClCompile Include="..\..\src\init.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\memory.c">
|
||||
<ClCompile Include="..\..\src\region.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\options.c">
|
||||
@ -43,6 +43,15 @@
|
||||
<ClCompile Include="..\..\src\stats.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\bitmap.inc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\random.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||
@ -72,4 +81,4 @@
|
||||
<UniqueIdentifier>{852a14ae-6dde-4e95-8077-ca705e97e5af}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -9,7 +9,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#define MIMALLOC_ATOMIC_H
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Atomics
|
||||
// Atomics
|
||||
// We need to be portable between C, C++, and MSVC.
|
||||
// ------------------------------------------------------
|
||||
|
||||
@ -23,20 +23,24 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
|
||||
#define mi_atomic_cast(tp,x) (volatile _Atomic(tp)*)(x)
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Atomic operations specialized for mimalloc
|
||||
// ------------------------------------------------------
|
||||
|
||||
// Atomically add a 64-bit value; returns the previous value.
|
||||
// Atomically add a 64-bit value; returns the previous value.
|
||||
// Note: not using _Atomic(int64_t) as it is only used for statistics.
|
||||
static inline void mi_atomic_add64(volatile int64_t* p, int64_t add);
|
||||
static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add);
|
||||
|
||||
// Atomically add a value; returns the previous value. Memory ordering is relaxed.
|
||||
static inline intptr_t mi_atomic_add(volatile _Atomic(intptr_t)* p, intptr_t add);
|
||||
static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add);
|
||||
|
||||
// Atomically compare and exchange a value; returns `true` if successful.
|
||||
// Atomically "and" a value; returns the previous value. Memory ordering is relaxed.
|
||||
static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x);
|
||||
|
||||
// Atomically "or" a value; returns the previous value. Memory ordering is relaxed.
|
||||
static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x);
|
||||
|
||||
// Atomically compare and exchange a value; returns `true` if successful.
|
||||
// May fail spuriously. Memory ordering as release on success, and relaxed on failure.
|
||||
// (Note: expected and desired are in opposite order from atomic_compare_exchange)
|
||||
static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected);
|
||||
@ -62,57 +66,57 @@ static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x);
|
||||
static inline void mi_atomic_yield(void);
|
||||
|
||||
|
||||
|
||||
// Atomically add a value; returns the previous value.
|
||||
static inline uintptr_t mi_atomic_addu(volatile _Atomic(uintptr_t)* p, uintptr_t add) {
|
||||
return (uintptr_t)mi_atomic_add((volatile _Atomic(intptr_t)*)p, (intptr_t)add);
|
||||
}
|
||||
// Atomically subtract a value; returns the previous value.
|
||||
static inline uintptr_t mi_atomic_subu(volatile _Atomic(uintptr_t)* p, uintptr_t sub) {
|
||||
return (uintptr_t)mi_atomic_add((volatile _Atomic(intptr_t)*)p, -((intptr_t)sub));
|
||||
static inline uintptr_t mi_atomic_sub(volatile _Atomic(uintptr_t)* p, uintptr_t sub) {
|
||||
return mi_atomic_add(p, (uintptr_t)(-((intptr_t)sub)));
|
||||
}
|
||||
|
||||
// Atomically increment a value; returns the incremented result.
|
||||
static inline uintptr_t mi_atomic_increment(volatile _Atomic(uintptr_t)* p) {
|
||||
return mi_atomic_addu(p, 1);
|
||||
return mi_atomic_add(p, 1);
|
||||
}
|
||||
|
||||
// Atomically decrement a value; returns the decremented result.
|
||||
static inline uintptr_t mi_atomic_decrement(volatile _Atomic(uintptr_t)* p) {
|
||||
return mi_atomic_subu(p, 1);
|
||||
return mi_atomic_sub(p, 1);
|
||||
}
|
||||
|
||||
// Atomically read a pointer; Memory order is relaxed.
|
||||
static inline void* mi_atomic_read_ptr_relaxed(volatile _Atomic(void*) const * p) {
|
||||
return (void*)mi_atomic_read_relaxed((const volatile _Atomic(uintptr_t)*)p);
|
||||
// Atomically add a signed value; returns the previous value.
|
||||
static inline intptr_t mi_atomic_addi(volatile _Atomic(intptr_t)* p, intptr_t add) {
|
||||
return (intptr_t)mi_atomic_add((volatile _Atomic(uintptr_t)*)p, (uintptr_t)add);
|
||||
}
|
||||
|
||||
// Atomically subtract a signed value; returns the previous value.
|
||||
static inline intptr_t mi_atomic_subi(volatile _Atomic(intptr_t)* p, intptr_t sub) {
|
||||
return (intptr_t)mi_atomic_addi(p,-sub);
|
||||
}
|
||||
|
||||
// Atomically read a pointer; Memory order is relaxed (i.e. no fence, only atomic).
|
||||
#define mi_atomic_read_ptr_relaxed(T,p) \
|
||||
(T*)(mi_atomic_read_relaxed((const volatile _Atomic(uintptr_t)*)(p)))
|
||||
|
||||
// Atomically read a pointer; Memory order is acquire.
|
||||
static inline void* mi_atomic_read_ptr(volatile _Atomic(void*) const * p) {
|
||||
return (void*)mi_atomic_read((const volatile _Atomic(uintptr_t)*)p);
|
||||
}
|
||||
#define mi_atomic_read_ptr(T,p) \
|
||||
(T*)(mi_atomic_read((const volatile _Atomic(uintptr_t)*)(p)))
|
||||
|
||||
// Atomically write a pointer
|
||||
static inline void mi_atomic_write_ptr(volatile _Atomic(void*)* p, void* x) {
|
||||
mi_atomic_write((volatile _Atomic(uintptr_t)*)p, (uintptr_t)x );
|
||||
}
|
||||
// Atomically write a pointer; Memory order is acquire.
|
||||
#define mi_atomic_write_ptr(T,p,x) \
|
||||
mi_atomic_write((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)x))
|
||||
|
||||
// Atomically compare and exchange a pointer; returns `true` if successful. May fail spuriously.
|
||||
// Memory order is release. (like a write)
|
||||
// (Note: expected and desired are in opposite order from atomic_compare_exchange)
|
||||
static inline bool mi_atomic_cas_ptr_weak(volatile _Atomic(void*)* p, void* desired, void* expected) {
|
||||
return mi_atomic_cas_weak((volatile _Atomic(uintptr_t)*)p, (uintptr_t)desired, (uintptr_t)expected);
|
||||
}
|
||||
|
||||
// Atomically compare and exchange a pointer; returns `true` if successful.
|
||||
#define mi_atomic_cas_ptr_weak(T,p,desired,expected) \
|
||||
mi_atomic_cas_weak((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)(desired)), (uintptr_t)((T*)(expected)))
|
||||
|
||||
// Atomically compare and exchange a pointer; returns `true` if successful. Memory order is acquire_release.
|
||||
// (Note: expected and desired are in opposite order from atomic_compare_exchange)
|
||||
static inline bool mi_atomic_cas_ptr_strong(volatile _Atomic(void*)* p, void* desired, void* expected) {
|
||||
return mi_atomic_cas_strong((volatile _Atomic(uintptr_t)*)p, (uintptr_t)desired, (uintptr_t)expected);
|
||||
}
|
||||
#define mi_atomic_cas_ptr_strong(T,p,desired,expected) \
|
||||
mi_atomic_cas_strong((volatile _Atomic(uintptr_t)*)(p),(uintptr_t)((T*)(desired)), (uintptr_t)((T*)(expected)))
|
||||
|
||||
// Atomically exchange a pointer value.
|
||||
static inline void* mi_atomic_exchange_ptr(volatile _Atomic(void*)* p, void* exchange) {
|
||||
return (void*)mi_atomic_exchange((volatile _Atomic(uintptr_t)*)p, (uintptr_t)exchange);
|
||||
}
|
||||
#define mi_atomic_exchange_ptr(T,p,exchange) \
|
||||
(T*)mi_atomic_exchange((volatile _Atomic(uintptr_t)*)(p), (uintptr_t)((T*)exchange))
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -121,38 +125,48 @@ static inline void* mi_atomic_exchange_ptr(volatile _Atomic(void*)* p, void* exc
|
||||
#include <intrin.h>
|
||||
#ifdef _WIN64
|
||||
typedef LONG64 msc_intptr_t;
|
||||
#define RC64(f) f##64
|
||||
#define MI_64(f) f##64
|
||||
#else
|
||||
typedef LONG msc_intptr_t;
|
||||
#define RC64(f) f
|
||||
#define MI_64(f) f
|
||||
#endif
|
||||
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 uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) {
|
||||
return (uintptr_t)MI_64(_InterlockedExchangeAdd)((volatile msc_intptr_t*)p, (msc_intptr_t)add);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x) {
|
||||
return (uintptr_t)MI_64(_InterlockedAnd)((volatile msc_intptr_t*)p, (msc_intptr_t)x);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x) {
|
||||
return (uintptr_t)MI_64(_InterlockedOr)((volatile msc_intptr_t*)p, (msc_intptr_t)x);
|
||||
}
|
||||
static inline bool mi_atomic_cas_strong(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) {
|
||||
return (expected == (uintptr_t)RC64(_InterlockedCompareExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)desired, (msc_intptr_t)expected));
|
||||
return (expected == (uintptr_t)MI_64(_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);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_exchange(volatile _Atomic(uintptr_t)* p, uintptr_t exchange) {
|
||||
return (uintptr_t)RC64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange);
|
||||
return (uintptr_t)MI_64(_InterlockedExchange)((volatile msc_intptr_t*)p, (msc_intptr_t)exchange);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_read(volatile _Atomic(uintptr_t) const* p) {
|
||||
return *p;
|
||||
}
|
||||
static inline uintptr_t mi_atomic_read_relaxed(volatile _Atomic(uintptr_t) const* p) {
|
||||
return mi_atomic_read(p);
|
||||
return *p;
|
||||
}
|
||||
static inline void mi_atomic_write(volatile _Atomic(uintptr_t)* p, uintptr_t x) {
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
*p = x;
|
||||
#else
|
||||
mi_atomic_exchange(p,x);
|
||||
#endif
|
||||
}
|
||||
static inline void mi_atomic_yield(void) {
|
||||
YieldProcessor();
|
||||
}
|
||||
static inline void mi_atomic_add64(volatile _Atomic(int64_t)* p, int64_t add) {
|
||||
static inline void mi_atomic_addi64(volatile _Atomic(int64_t)* p, int64_t add) {
|
||||
#ifdef _WIN64
|
||||
mi_atomic_add(p,add);
|
||||
mi_atomic_addi(p,add);
|
||||
#else
|
||||
int64_t current;
|
||||
int64_t sum;
|
||||
@ -169,14 +183,22 @@ static inline void mi_atomic_add64(volatile _Atomic(int64_t)* p, int64_t add) {
|
||||
#else
|
||||
#define MI_USING_STD
|
||||
#endif
|
||||
static inline void mi_atomic_add64(volatile int64_t* p, int64_t add) {
|
||||
static inline void mi_atomic_addi64(volatile int64_t* p, int64_t add) {
|
||||
MI_USING_STD
|
||||
atomic_fetch_add_explicit((volatile _Atomic(int64_t)*)p, add, memory_order_relaxed);
|
||||
}
|
||||
static inline intptr_t mi_atomic_add(volatile _Atomic(intptr_t)* p, intptr_t add) {
|
||||
static inline uintptr_t mi_atomic_add(volatile _Atomic(uintptr_t)* p, uintptr_t add) {
|
||||
MI_USING_STD
|
||||
return atomic_fetch_add_explicit(p, add, memory_order_relaxed);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_and(volatile _Atomic(uintptr_t)* p, uintptr_t x) {
|
||||
MI_USING_STD
|
||||
return atomic_fetch_and_explicit(p, x, memory_order_relaxed);
|
||||
}
|
||||
static inline uintptr_t mi_atomic_or(volatile _Atomic(uintptr_t)* p, uintptr_t x) {
|
||||
MI_USING_STD
|
||||
return atomic_fetch_or_explicit(p, x, memory_order_relaxed);
|
||||
}
|
||||
static inline bool mi_atomic_cas_weak(volatile _Atomic(uintptr_t)* p, uintptr_t desired, uintptr_t expected) {
|
||||
MI_USING_STD
|
||||
return atomic_compare_exchange_weak_explicit(p, &expected, desired, memory_order_release, memory_order_relaxed);
|
||||
|
@ -10,44 +10,53 @@ 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__) || defined(__OpenBSD__))
|
||||
#if defined(MI_MALLOC_OVERRIDE) && (defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__))
|
||||
#define MI_TLS_RECURSE_GUARD
|
||||
#endif
|
||||
|
||||
#if (MI_DEBUG>0)
|
||||
#define mi_trace_message(...) _mi_trace_message(__VA_ARGS__)
|
||||
#else
|
||||
#define mi_trace_message(...)
|
||||
#define mi_trace_message(...)
|
||||
#endif
|
||||
|
||||
#define MI_CACHE_LINE 64
|
||||
#if defined(_MSC_VER)
|
||||
#define mi_decl_noinline __declspec(noinline)
|
||||
#define mi_attr_noreturn
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define mi_decl_noinline __attribute__((noinline))
|
||||
#define mi_attr_noreturn __attribute__((noreturn))
|
||||
#pragma warning(disable:4127) // suppress constant conditional warning (due to MI_SECURE paths)
|
||||
#define mi_decl_noinline __declspec(noinline)
|
||||
#define mi_decl_thread __declspec(thread)
|
||||
#define mi_decl_cache_align __declspec(align(MI_CACHE_LINE))
|
||||
#elif (defined(__GNUC__) && (__GNUC__>=3)) // includes clang and icc
|
||||
#define mi_decl_noinline __attribute__((noinline))
|
||||
#define mi_decl_thread __thread
|
||||
#define mi_decl_cache_align __attribute__((aligned(MI_CACHE_LINE)))
|
||||
#else
|
||||
#define mi_decl_noinline
|
||||
#define mi_attr_noreturn
|
||||
#define mi_decl_thread __thread // hope for the best :-)
|
||||
#define mi_decl_cache_align
|
||||
#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, ...);
|
||||
void _mi_error_message(const char* fmt, ...);
|
||||
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
|
||||
void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...);
|
||||
void _mi_warning_message(const char* fmt, ...);
|
||||
void _mi_verbose_message(const char* fmt, ...);
|
||||
void _mi_trace_message(const char* fmt, ...);
|
||||
void _mi_options_init(void);
|
||||
void _mi_fatal_error(const char* fmt, ...) mi_attr_noreturn;
|
||||
void _mi_error_message(int err, const char* fmt, ...);
|
||||
|
||||
// "init.c"
|
||||
// random.c
|
||||
void _mi_random_init(mi_random_ctx_t* ctx);
|
||||
void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* new_ctx);
|
||||
uintptr_t _mi_random_next(mi_random_ctx_t* ctx);
|
||||
uintptr_t _mi_heap_random_next(mi_heap_t* heap);
|
||||
static inline uintptr_t _mi_random_shuffle(uintptr_t x);
|
||||
|
||||
// init.c
|
||||
extern mi_stats_t _mi_stats_main;
|
||||
extern const mi_page_t _mi_page_empty;
|
||||
bool _mi_is_main_thread(void);
|
||||
uintptr_t _mi_random_shuffle(uintptr_t x);
|
||||
uintptr_t _mi_random_init(uintptr_t seed /* can be zero */);
|
||||
bool _mi_preloading(); // true while the C runtime is not ready
|
||||
|
||||
// os.c
|
||||
@ -59,23 +68,24 @@ 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);
|
||||
void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats);
|
||||
void _mi_mem_free(void* p, size_t size, size_t id, bool fully_committed, bool any_reset, mi_os_tld_t* tld);
|
||||
|
||||
bool _mi_mem_reset(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_reset(void* p, size_t size, mi_os_tld_t* tld);
|
||||
bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld);
|
||||
bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld);
|
||||
bool _mi_mem_protect(void* addr, size_t size);
|
||||
bool _mi_mem_unprotect(void* addr, size_t size);
|
||||
|
||||
void _mi_mem_collect(mi_stats_t* stats);
|
||||
void _mi_mem_collect(mi_os_tld_t* tld);
|
||||
|
||||
// "segment.c"
|
||||
mi_page_t* _mi_segment_page_alloc(size_t block_wsize, mi_segments_tld_t* tld, mi_os_tld_t* os_tld);
|
||||
mi_page_t* _mi_segment_page_alloc(mi_heap_t* heap, size_t block_wsize, mi_segments_tld_t* tld, mi_os_tld_t* os_tld);
|
||||
void _mi_segment_page_free(mi_page_t* page, bool force, mi_segments_tld_t* tld);
|
||||
void _mi_segment_page_abandon(mi_page_t* page, mi_segments_tld_t* tld);
|
||||
bool _mi_segment_try_reclaim_abandoned( mi_heap_t* heap, bool try_all, mi_segments_tld_t* tld);
|
||||
uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t block_size, size_t* page_size, size_t* pre_size); // page start for any page
|
||||
void _mi_segment_thread_collect(mi_segments_tld_t* tld);
|
||||
uint8_t* _mi_segment_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t block_size, size_t* page_size); // page start for any page
|
||||
void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld);
|
||||
void _mi_abandoned_await_readers(void);
|
||||
|
||||
// "page.c"
|
||||
void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc;
|
||||
@ -85,8 +95,9 @@ void _mi_page_unfull(mi_page_t* page);
|
||||
void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force); // free the page
|
||||
void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq); // abandon the page, to be picked up by another thread...
|
||||
void _mi_heap_delayed_free(mi_heap_t* heap);
|
||||
void _mi_heap_collect_retired(mi_heap_t* heap, bool force);
|
||||
|
||||
void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay);
|
||||
void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never);
|
||||
size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue_t* append);
|
||||
void _mi_deferred_free(mi_heap_t* heap, bool force);
|
||||
|
||||
@ -100,13 +111,14 @@ uint8_t _mi_bsr(uintptr_t x); // bit-scan-right, used on BSD i
|
||||
// "heap.c"
|
||||
void _mi_heap_destroy_pages(mi_heap_t* heap);
|
||||
void _mi_heap_collect_abandon(mi_heap_t* heap);
|
||||
uintptr_t _mi_heap_random(mi_heap_t* heap);
|
||||
void _mi_heap_set_default_direct(mi_heap_t* heap);
|
||||
|
||||
// "stats.c"
|
||||
void _mi_stats_done(mi_stats_t* stats);
|
||||
double _mi_clock_end(double start);
|
||||
double _mi_clock_start(void);
|
||||
|
||||
mi_msecs_t _mi_clock_now(void);
|
||||
mi_msecs_t _mi_clock_end(mi_msecs_t start);
|
||||
mi_msecs_t _mi_clock_start(void);
|
||||
|
||||
// "alloc.c"
|
||||
void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept; // called from `_mi_malloc_generic`
|
||||
@ -138,13 +150,36 @@ bool _mi_page_is_valid(mi_page_t* page);
|
||||
#endif
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Error codes passed to `_mi_fatal_error`
|
||||
All are recoverable but EFAULT is a serious error and aborts by default in secure mode.
|
||||
For portability define undefined error codes using common Unix codes:
|
||||
<https://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html>
|
||||
----------------------------------------------------------- */
|
||||
#include <errno.h>
|
||||
#ifndef EAGAIN // double free
|
||||
#define EAGAIN (11)
|
||||
#endif
|
||||
#ifndef ENOMEM // out of memory
|
||||
#define ENOMEM (12)
|
||||
#endif
|
||||
#ifndef EFAULT // corrupted free-list or meta-data
|
||||
#define EFAULT (14)
|
||||
#endif
|
||||
#ifndef EINVAL // trying to free an invalid pointer
|
||||
#define EINVAL (22)
|
||||
#endif
|
||||
#ifndef EOVERFLOW // count*size overflow
|
||||
#define EOVERFLOW (75)
|
||||
#endif
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Inlined definitions
|
||||
----------------------------------------------------------- */
|
||||
#define UNUSED(x) (void)(x)
|
||||
#if (MI_DEBUG>0)
|
||||
#define UNUSED_RELEASE(x)
|
||||
#if (MI_DEBUG>0)
|
||||
#define UNUSED_RELEASE(x)
|
||||
#else
|
||||
#define UNUSED_RELEASE(x) UNUSED(x)
|
||||
#endif
|
||||
@ -158,25 +193,6 @@ bool _mi_page_is_valid(mi_page_t* page);
|
||||
#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x)
|
||||
|
||||
|
||||
// Overflow detecting multiply
|
||||
#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 <limits.h> // UINT_MAX, ULONG_MAX
|
||||
#if (SIZE_MAX == UINT_MAX)
|
||||
return __builtin_umul_overflow(count, size, total);
|
||||
#elif (SIZE_MAX == ULONG_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;
|
||||
return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
|
||||
&& size > 0 && (SIZE_MAX / size) < count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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);
|
||||
@ -184,6 +200,7 @@ static inline bool _mi_is_power_of_two(uintptr_t x) {
|
||||
|
||||
// Align upwards
|
||||
static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) {
|
||||
mi_assert_internal(alignment != 0);
|
||||
uintptr_t mask = alignment - 1;
|
||||
if ((alignment & mask) == 0) { // power of two?
|
||||
return ((sz + mask) & ~mask);
|
||||
@ -193,6 +210,12 @@ static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) {
|
||||
}
|
||||
}
|
||||
|
||||
// Divide upwards: `s <= _mi_divide_up(s,d)*d < s+d`.
|
||||
static inline uintptr_t _mi_divide_up(uintptr_t size, size_t divider) {
|
||||
mi_assert_internal(divider != 0);
|
||||
return (divider == 0 ? size : ((size + divider - 1) / divider));
|
||||
}
|
||||
|
||||
// Is memory zero initialized?
|
||||
static inline bool mi_mem_is_zero(void* p, size_t size) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
@ -209,6 +232,40 @@ static inline size_t _mi_wsize_from_size(size_t size) {
|
||||
}
|
||||
|
||||
|
||||
// Overflow detecting multiply
|
||||
static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) {
|
||||
#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
|
||||
#include <limits.h> // UINT_MAX, ULONG_MAX
|
||||
#if (SIZE_MAX == UINT_MAX)
|
||||
return __builtin_umul_overflow(count, size, total);
|
||||
#elif (SIZE_MAX == ULONG_MAX)
|
||||
return __builtin_umull_overflow(count, size, total);
|
||||
#else
|
||||
return __builtin_umulll_overflow(count, size, total);
|
||||
#endif
|
||||
#else /* __builtin_umul_overflow is unavailable */
|
||||
#define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX)
|
||||
*total = count * size;
|
||||
return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
|
||||
&& size > 0 && (SIZE_MAX / size) < count);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Safe multiply `count*size` into `total`; return `true` on overflow.
|
||||
static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) {
|
||||
if (count==1) { // quick check for the case where count is one (common for C++ allocators)
|
||||
*total = size;
|
||||
return false;
|
||||
}
|
||||
else if (mi_unlikely(mi_mul_overflow(count, size, total))) {
|
||||
_mi_error_message(EOVERFLOW, "allocation request too large (%zu * %zu bytes)\n", count, size);
|
||||
*total = SIZE_MAX;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
The thread local default heap
|
||||
----------------------------------------------------------- */
|
||||
@ -221,7 +278,7 @@ extern mi_decl_thread mi_heap_t* _mi_heap_default; // default heap to allocate
|
||||
|
||||
static inline mi_heap_t* mi_get_default_heap(void) {
|
||||
#ifdef MI_TLS_RECURSE_GUARD
|
||||
// on some platforms, like macOS, the dynamic loader calls `malloc`
|
||||
// on some BSD platforms, like macOS, the dynamic loader calls `malloc`
|
||||
// to initialize thread local data. To avoid recursion, we need to avoid
|
||||
// accessing the thread local `_mi_default_heap` until our module is loaded
|
||||
// and use the statically allocated main heap until that time.
|
||||
@ -279,7 +336,7 @@ static inline mi_segment_t* _mi_page_segment(const mi_page_t* page) {
|
||||
static inline uintptr_t _mi_segment_page_idx_of(const mi_segment_t* segment, const void* p) {
|
||||
// if (segment->page_size > MI_SEGMENT_SIZE) return &segment->pages[0]; // huge pages
|
||||
ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment;
|
||||
mi_assert_internal(diff >= 0 && diff < MI_SEGMENT_SIZE);
|
||||
mi_assert_internal(diff >= 0 && (size_t)diff < MI_SEGMENT_SIZE);
|
||||
uintptr_t idx = (uintptr_t)diff >> segment->page_shift;
|
||||
mi_assert_internal(idx < segment->capacity);
|
||||
mi_assert_internal(segment->page_kind <= MI_PAGE_MEDIUM || idx == 0);
|
||||
@ -294,7 +351,9 @@ static inline mi_page_t* _mi_segment_page_of(const mi_segment_t* segment, const
|
||||
|
||||
// Quick page start for initialized pages
|
||||
static inline uint8_t* _mi_page_start(const mi_segment_t* segment, const mi_page_t* page, size_t* page_size) {
|
||||
return _mi_segment_page_start(segment, page, page->block_size, page_size);
|
||||
const size_t bsize = page->xblock_size;
|
||||
mi_assert_internal(bsize > 0 && (bsize%sizeof(void*)) == 0);
|
||||
return _mi_segment_page_start(segment, page, bsize, page_size, NULL);
|
||||
}
|
||||
|
||||
// Get the page containing the pointer
|
||||
@ -302,7 +361,40 @@ static inline mi_page_t* _mi_ptr_page(void* p) {
|
||||
return _mi_segment_page_of(_mi_ptr_segment(p), p);
|
||||
}
|
||||
|
||||
// Get the block size of a page (special cased for huge objects)
|
||||
static inline size_t mi_page_block_size(const mi_page_t* page) {
|
||||
const size_t bsize = page->xblock_size;
|
||||
mi_assert_internal(bsize > 0);
|
||||
if (mi_likely(bsize < MI_HUGE_BLOCK_SIZE)) {
|
||||
return bsize;
|
||||
}
|
||||
else {
|
||||
size_t psize;
|
||||
_mi_segment_page_start(_mi_page_segment(page), page, bsize, &psize, NULL);
|
||||
return psize;
|
||||
}
|
||||
}
|
||||
|
||||
// Thread free access
|
||||
static inline mi_block_t* mi_page_thread_free(const mi_page_t* page) {
|
||||
return (mi_block_t*)(mi_atomic_read_relaxed(&page->xthread_free) & ~3);
|
||||
}
|
||||
|
||||
static inline mi_delayed_t mi_page_thread_free_flag(const mi_page_t* page) {
|
||||
return (mi_delayed_t)(mi_atomic_read_relaxed(&page->xthread_free) & 3);
|
||||
}
|
||||
|
||||
// Heap access
|
||||
static inline mi_heap_t* mi_page_heap(const mi_page_t* page) {
|
||||
return (mi_heap_t*)(mi_atomic_read_relaxed(&page->xheap));
|
||||
}
|
||||
|
||||
static inline void mi_page_set_heap(mi_page_t* page, mi_heap_t* heap) {
|
||||
mi_assert_internal(mi_page_thread_free_flag(page) != MI_DELAYED_FREEING);
|
||||
mi_atomic_write(&page->xheap,(uintptr_t)heap);
|
||||
}
|
||||
|
||||
// Thread free flag helpers
|
||||
static inline mi_block_t* mi_tf_block(mi_thread_free_t tf) {
|
||||
return (mi_block_t*)(tf & ~0x03);
|
||||
}
|
||||
@ -319,36 +411,30 @@ static inline mi_thread_free_t mi_tf_set_block(mi_thread_free_t tf, mi_block_t*
|
||||
return mi_tf_make(block, mi_tf_delayed(tf));
|
||||
}
|
||||
|
||||
// are all blocks in a page freed?
|
||||
// are all blocks in a page freed?
|
||||
// note: needs up-to-date used count, (as the `xthread_free` list may not be empty). see `_mi_page_collect_free`.
|
||||
static inline bool mi_page_all_free(const mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
return (page->used - page->thread_freed == 0);
|
||||
return (page->used == 0);
|
||||
}
|
||||
|
||||
// are there immediately available blocks
|
||||
// are there any available blocks?
|
||||
static inline bool mi_page_has_any_available(const mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL && page->reserved > 0);
|
||||
return (page->used < page->reserved || (mi_page_thread_free(page) != NULL));
|
||||
}
|
||||
|
||||
// are there immediately available blocks, i.e. blocks available on the free list.
|
||||
static inline bool mi_page_immediate_available(const mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
return (page->free != NULL);
|
||||
}
|
||||
// are there free blocks in this page?
|
||||
static inline bool mi_page_has_free(mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
bool hasfree = (mi_page_immediate_available(page) || page->local_free != NULL || (mi_tf_block(page->thread_free) != NULL));
|
||||
mi_assert_internal(hasfree || page->used - page->thread_freed == page->capacity);
|
||||
return hasfree;
|
||||
}
|
||||
|
||||
// are all blocks in use?
|
||||
static inline bool mi_page_all_used(mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
return !mi_page_has_free(page);
|
||||
}
|
||||
|
||||
// is more than 7/8th of a page in use?
|
||||
static inline bool mi_page_mostly_used(const mi_page_t* page) {
|
||||
if (page==NULL) return true;
|
||||
uint16_t frac = page->reserved / 8U;
|
||||
return (page->reserved - page->used + page->thread_freed <= frac);
|
||||
return (page->reserved - page->used <= frac);
|
||||
}
|
||||
|
||||
static inline mi_page_queue_t* mi_page_queue(const mi_heap_t* heap, size_t size) {
|
||||
@ -377,12 +463,30 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) {
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Encoding/Decoding the free list next pointers
|
||||
// Note: we pass a `null` value to be used as the `NULL` value for the
|
||||
// end of a free list. This is to prevent the cookie itself to ever
|
||||
// be present among user blocks (as `cookie^0==cookie`).
|
||||
// -------------------------------------------------------------------
|
||||
/* -------------------------------------------------------------------
|
||||
Encoding/Decoding the free list next pointers
|
||||
|
||||
This is to protect against buffer overflow exploits where the
|
||||
free list is mutated. Many hardened allocators xor the next pointer `p`
|
||||
with a secret key `k1`, as `p^k1`. This prevents overwriting with known
|
||||
values but might be still too weak: if the attacker can guess
|
||||
the pointer `p` this can reveal `k1` (since `p^k1^p == k1`).
|
||||
Moreover, if multiple blocks can be read as well, the attacker can
|
||||
xor both as `(p1^k1) ^ (p2^k1) == p1^p2` which may reveal a lot
|
||||
about the pointers (and subsequently `k1`).
|
||||
|
||||
Instead mimalloc uses an extra key `k2` and encodes as `((p^k2)<<<k1)+k1`.
|
||||
Since these operations are not associative, the above approaches do not
|
||||
work so well any more even if the `p` can be guesstimated. For example,
|
||||
for the read case we can subtract two entries to discard the `+k1` term,
|
||||
but that leads to `((p1^k2)<<<k1) - ((p2^k2)<<<k1)` at best.
|
||||
We include the left-rotation since xor and addition are otherwise linear
|
||||
in the lowest bit. Finally, both keys are unique per page which reduces
|
||||
the re-use of keys by a large factor.
|
||||
|
||||
We also pass a separate `null` value to be used as `NULL` or otherwise
|
||||
`(k2<<<k1)+k1` would appear (too) often as a sentinel value.
|
||||
------------------------------------------------------------------- */
|
||||
|
||||
static inline bool mi_is_in_same_segment(const void* p, const void* q) {
|
||||
return (_mi_ptr_segment(p) == _mi_ptr_segment(q));
|
||||
@ -397,52 +501,103 @@ static inline bool mi_is_in_same_page(const void* p, const void* q) {
|
||||
return (idxp == idxq);
|
||||
}
|
||||
|
||||
static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, uintptr_t cookie ) {
|
||||
static inline uintptr_t mi_rotl(uintptr_t x, uintptr_t shift) {
|
||||
shift %= MI_INTPTR_BITS;
|
||||
return ((x << shift) | (x >> (MI_INTPTR_BITS - shift)));
|
||||
}
|
||||
static inline uintptr_t mi_rotr(uintptr_t x, uintptr_t shift) {
|
||||
shift %= MI_INTPTR_BITS;
|
||||
return ((x >> shift) | (x << (MI_INTPTR_BITS - shift)));
|
||||
}
|
||||
|
||||
static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, uintptr_t key1, uintptr_t key2 ) {
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
mi_block_t* b = (mi_block_t*)(block->next ^ cookie);
|
||||
mi_block_t* b = (mi_block_t*)(mi_rotr(block->next - key1, key1) ^ key2);
|
||||
if (mi_unlikely((void*)b==null)) { b = NULL; }
|
||||
return b;
|
||||
#else
|
||||
UNUSED(cookie); UNUSED(null);
|
||||
UNUSED(key1); UNUSED(key2); UNUSED(null);
|
||||
return (mi_block_t*)block->next;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, uintptr_t cookie) {
|
||||
static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, uintptr_t key1, uintptr_t key2) {
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
if (mi_unlikely(next==NULL)) { next = (mi_block_t*)null; }
|
||||
block->next = (mi_encoded_t)next ^ cookie;
|
||||
block->next = mi_rotl((uintptr_t)next ^ key2, key1) + key1;
|
||||
#else
|
||||
UNUSED(cookie); UNUSED(null);
|
||||
UNUSED(key1); UNUSED(key2); UNUSED(null);
|
||||
block->next = (mi_encoded_t)next;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) {
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
mi_block_t* next = mi_block_nextx(page,block,page->cookie);
|
||||
// check for free list corruption: is `next` at least in our segment range?
|
||||
mi_block_t* next = mi_block_nextx(page,block,page->key[0],page->key[1]);
|
||||
// check for free list corruption: is `next` at least in the same page?
|
||||
// TODO: check if `next` is `page->block_size` aligned?
|
||||
if (next!=NULL && !mi_is_in_same_page(block, next)) {
|
||||
_mi_fatal_error("corrupted free list entry of size %zub at %p: value 0x%zx\n", page->block_size, block, (uintptr_t)next);
|
||||
if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) {
|
||||
_mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
|
||||
next = NULL;
|
||||
}
|
||||
}
|
||||
return next;
|
||||
#else
|
||||
UNUSED(page);
|
||||
return mi_block_nextx(page,block,0);
|
||||
return mi_block_nextx(page,block,0,0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) {
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
mi_block_set_nextx(page,block,next, page->cookie);
|
||||
mi_block_set_nextx(page,block,next, page->key[0], page->key[1]);
|
||||
#else
|
||||
UNUSED(page);
|
||||
mi_block_set_nextx(page,block, next,0);
|
||||
mi_block_set_nextx(page,block, next,0,0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Fast "random" shuffle
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
static inline uintptr_t _mi_random_shuffle(uintptr_t x) {
|
||||
if (x==0) { x = 17; } // ensure we don't get stuck in generating zeros
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
// by Sebastiano Vigna, see: <http://xoshiro.di.unimi.it/splitmix64.c>
|
||||
x ^= x >> 30;
|
||||
x *= 0xbf58476d1ce4e5b9UL;
|
||||
x ^= x >> 27;
|
||||
x *= 0x94d049bb133111ebUL;
|
||||
x ^= x >> 31;
|
||||
#elif (MI_INTPTR_SIZE==4)
|
||||
// by Chris Wellons, see: <https://nullprogram.com/blog/2018/07/31/>
|
||||
x ^= x >> 16;
|
||||
x *= 0x7feb352dUL;
|
||||
x ^= x >> 15;
|
||||
x *= 0x846ca68bUL;
|
||||
x ^= x >> 16;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Optimize numa node access for the common case (= one node)
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
int _mi_os_numa_node_get(mi_os_tld_t* tld);
|
||||
size_t _mi_os_numa_node_count_get(void);
|
||||
|
||||
extern size_t _mi_numa_node_count;
|
||||
static inline int _mi_os_numa_node(mi_os_tld_t* tld) {
|
||||
if (mi_likely(_mi_numa_node_count == 1)) return 0;
|
||||
else return _mi_os_numa_node_get(tld);
|
||||
}
|
||||
static inline size_t _mi_os_numa_node_count(void) {
|
||||
if (mi_likely(_mi_numa_node_count>0)) return _mi_numa_node_count;
|
||||
else return _mi_os_numa_node_count_get();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Getting the thread id should be performant
|
||||
// as it is called in the fast path of `_mi_free`,
|
||||
|
@ -46,7 +46,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
|
||||
// Encoded free lists allow detection of corrupted free lists
|
||||
// and can detect buffer overflows and double `free`s.
|
||||
#if (MI_SECURE>=3 || MI_DEBUG>=1)
|
||||
#if (MI_SECURE>=3 || MI_DEBUG>=1)
|
||||
#define MI_ENCODE_FREELIST 1
|
||||
#endif
|
||||
|
||||
@ -76,6 +76,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#endif
|
||||
|
||||
#define MI_INTPTR_SIZE (1<<MI_INTPTR_SHIFT)
|
||||
#define MI_INTPTR_BITS (MI_INTPTR_SIZE*8)
|
||||
|
||||
#define KiB ((size_t)1024)
|
||||
#define MiB (KiB*KiB)
|
||||
@ -93,12 +94,12 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#define MI_SEGMENT_SHIFT ( MI_LARGE_PAGE_SHIFT) // 4mb
|
||||
|
||||
// Derived constants
|
||||
#define MI_SEGMENT_SIZE (1<<MI_SEGMENT_SHIFT)
|
||||
#define MI_SEGMENT_SIZE (1UL<<MI_SEGMENT_SHIFT)
|
||||
#define MI_SEGMENT_MASK ((uintptr_t)MI_SEGMENT_SIZE - 1)
|
||||
|
||||
#define MI_SMALL_PAGE_SIZE (1<<MI_SMALL_PAGE_SHIFT)
|
||||
#define MI_MEDIUM_PAGE_SIZE (1<<MI_MEDIUM_PAGE_SHIFT)
|
||||
#define MI_LARGE_PAGE_SIZE (1<<MI_LARGE_PAGE_SHIFT)
|
||||
#define MI_SMALL_PAGE_SIZE (1UL<<MI_SMALL_PAGE_SHIFT)
|
||||
#define MI_MEDIUM_PAGE_SIZE (1UL<<MI_MEDIUM_PAGE_SHIFT)
|
||||
#define MI_LARGE_PAGE_SIZE (1UL<<MI_LARGE_PAGE_SHIFT)
|
||||
|
||||
#define MI_SMALL_PAGES_PER_SEGMENT (MI_SEGMENT_SIZE/MI_SMALL_PAGE_SIZE)
|
||||
#define MI_MEDIUM_PAGES_PER_SEGMENT (MI_SEGMENT_SIZE/MI_MEDIUM_PAGE_SIZE)
|
||||
@ -108,8 +109,8 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
// (Except for large pages since huge objects are allocated in 4MiB chunks)
|
||||
#define MI_SMALL_OBJ_SIZE_MAX (MI_SMALL_PAGE_SIZE/4) // 16kb
|
||||
#define MI_MEDIUM_OBJ_SIZE_MAX (MI_MEDIUM_PAGE_SIZE/4) // 128kb
|
||||
#define MI_LARGE_OBJ_SIZE_MAX (MI_LARGE_PAGE_SIZE/2) // 2mb
|
||||
#define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
|
||||
#define MI_LARGE_OBJ_SIZE_MAX (MI_LARGE_PAGE_SIZE/2) // 2mb
|
||||
#define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
|
||||
#define MI_HUGE_OBJ_SIZE_MAX (2*MI_INTPTR_SIZE*MI_SEGMENT_SIZE) // (must match MI_REGION_MAX_ALLOC_SIZE in memory.c)
|
||||
|
||||
// Minimal alignment necessary. On most platforms 16 bytes are needed
|
||||
@ -123,6 +124,9 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#error "define more bins"
|
||||
#endif
|
||||
|
||||
// Used as a special value to encode block sizes in 32 bits.
|
||||
#define MI_HUGE_BLOCK_SIZE ((uint32_t)MI_HUGE_OBJ_SIZE_MAX)
|
||||
|
||||
// The free lists use encoded next fields
|
||||
// (Only actually encodes when MI_ENCODED_FREELIST is defined.)
|
||||
typedef uintptr_t mi_encoded_t;
|
||||
@ -135,21 +139,21 @@ typedef struct mi_block_s {
|
||||
|
||||
// The delayed flags are used for efficient multi-threaded free-ing
|
||||
typedef enum mi_delayed_e {
|
||||
MI_NO_DELAYED_FREE = 0,
|
||||
MI_USE_DELAYED_FREE = 1,
|
||||
MI_DELAYED_FREEING = 2,
|
||||
MI_NEVER_DELAYED_FREE = 3
|
||||
MI_USE_DELAYED_FREE = 0, // push on the owning heap thread delayed list
|
||||
MI_DELAYED_FREEING = 1, // temporary: another thread is accessing the owning heap
|
||||
MI_NO_DELAYED_FREE = 2, // optimize: push on page local thread free queue if another block is already in the heap thread delayed free list
|
||||
MI_NEVER_DELAYED_FREE = 3 // sticky, only resets on page reclaim
|
||||
} mi_delayed_t;
|
||||
|
||||
|
||||
// The `in_full` and `has_aligned` page flags are put in a union to efficiently
|
||||
// The `in_full` and `has_aligned` page flags are put in a union to efficiently
|
||||
// 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;
|
||||
} x;
|
||||
} mi_page_flags_t;
|
||||
|
||||
// Thread free list.
|
||||
@ -166,14 +170,28 @@ typedef uintptr_t mi_thread_free_t;
|
||||
// implement a monotonic heartbeat. The `thread_free` list is needed for
|
||||
// avoiding atomic operations in the common case.
|
||||
//
|
||||
// `used - thread_freed` == actual blocks that are in use (alive)
|
||||
// `used - thread_freed + |free| + |local_free| == capacity`
|
||||
//
|
||||
// note: we don't count `freed` (as |free|) instead of `used` to reduce
|
||||
// the number of memory accesses in the `mi_page_all_free` function(s).
|
||||
// note: the funny layout here is due to:
|
||||
// - access is optimized for `mi_free` and `mi_page_alloc`
|
||||
// - using `uint16_t` does not seem to slow things down
|
||||
// `used - |thread_free|` == actual blocks that are in use (alive)
|
||||
// `used - |thread_free| + |free| + |local_free| == capacity`
|
||||
//
|
||||
// We don't count `freed` (as |free|) but use `used` to reduce
|
||||
// the number of memory accesses in the `mi_page_all_free` function(s).
|
||||
//
|
||||
// Notes:
|
||||
// - Access is optimized for `mi_free` and `mi_page_alloc` (in `alloc.c`)
|
||||
// - Using `uint16_t` does not seem to slow things down
|
||||
// - The size is 8 words on 64-bit which helps the page index calculations
|
||||
// (and 10 words on 32-bit, and encoded free lists add 2 words. Sizes 10
|
||||
// and 12 are still good for address calculation)
|
||||
// - To limit the structure size, the `xblock_size` is 32-bits only; for
|
||||
// blocks > MI_HUGE_BLOCK_SIZE the size is determined from the segment page size
|
||||
// - `thread_free` uses the bottom bits as a delayed-free flags to optimize
|
||||
// concurrent frees where only the first concurrent free adds to the owning
|
||||
// heap `thread_delayed_free` list (see `alloc.c:mi_free_block_mt`).
|
||||
// The invariant is that no-delayed-free is only set if there is
|
||||
// at least one block that will be added, or as already been added, to
|
||||
// the owning heap `thread_delayed_free` list. This guarantees that pages
|
||||
// will be freed correctly even if only other threads free blocks.
|
||||
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]`
|
||||
@ -181,34 +199,27 @@ typedef struct mi_page_s {
|
||||
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`
|
||||
uint16_t reserved; // number of blocks reserved in memory
|
||||
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
|
||||
uint8_t is_zero:1; // `true` if the blocks in the free list are zero initialized
|
||||
uint8_t retire_expire:7; // expiration count for retired blocks
|
||||
|
||||
mi_block_t* free; // list of available free blocks (`malloc` allocates from this list)
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
uintptr_t cookie; // random cookie to encode the free lists
|
||||
uintptr_t key[2]; // two random keys to encode the free lists (see `_mi_block_next`)
|
||||
#endif
|
||||
size_t used; // number of blocks in use (including blocks in `local_free` and `thread_free`)
|
||||
|
||||
mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`)
|
||||
volatile _Atomic(uintptr_t) thread_freed; // at least this number of blocks are in `thread_free`
|
||||
volatile _Atomic(mi_thread_free_t) thread_free; // list of deferred free blocks freed by other threads
|
||||
uint32_t used; // number of blocks in use (including blocks in `local_free` and `thread_free`)
|
||||
uint32_t xblock_size; // size available in each block (always `>0`)
|
||||
|
||||
// less accessed info
|
||||
size_t block_size; // size available in each block (always `>0`)
|
||||
mi_heap_t* heap; // the owning heap
|
||||
mi_block_t* local_free; // list of deferred free blocks by this thread (migrates to `free`)
|
||||
volatile _Atomic(mi_thread_free_t) xthread_free; // list of deferred free blocks freed by other threads
|
||||
volatile _Atomic(uintptr_t) xheap;
|
||||
|
||||
struct mi_page_s* next; // next page owned by this thread with the same `block_size`
|
||||
struct mi_page_s* prev; // previous page owned by this thread with the same `block_size`
|
||||
|
||||
// improve page index calculation
|
||||
// without padding: 10 words on 64-bit, 11 on 32-bit. Secure adds one word
|
||||
#if (MI_INTPTR_SIZE==8 && defined(MI_ENCODE_FREELIST)) || (MI_INTPTR_SIZE==4 && !defined(MI_ENCODE_FREELIST))
|
||||
void* padding[1]; // 12 words on 64-bit with cookie, 12 words on 32-bit plain
|
||||
#endif
|
||||
} mi_page_t;
|
||||
|
||||
|
||||
@ -226,19 +237,21 @@ typedef enum mi_page_kind_e {
|
||||
typedef struct mi_segment_s {
|
||||
// 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_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* 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`)
|
||||
struct mi_segment_s* abandoned_next;
|
||||
size_t abandoned; // abandoned pages (i.e. the original owning thread stopped) (`abandoned <= used`)
|
||||
size_t abandoned_visits; // count how often this segment is visited in the abandoned list (to force reclaim it it is too long)
|
||||
|
||||
size_t used; // count of pages in use (`used <= capacity`)
|
||||
size_t capacity; // count of available pages (`#free + used`)
|
||||
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`
|
||||
uintptr_t cookie; // verify addresses in secure mode: `_mi_ptr_cookie(segment) == segment->cookie`
|
||||
|
||||
// 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`).
|
||||
@ -273,6 +286,14 @@ typedef struct mi_page_queue_s {
|
||||
|
||||
#define MI_BIN_FULL (MI_BIN_HUGE+1)
|
||||
|
||||
// Random context
|
||||
typedef struct mi_random_cxt_s {
|
||||
uint32_t input[16];
|
||||
uint32_t output[16];
|
||||
int output_available;
|
||||
} mi_random_ctx_t;
|
||||
|
||||
|
||||
// A heap owns a set of pages.
|
||||
struct mi_heap_s {
|
||||
mi_tld_t* tld;
|
||||
@ -280,8 +301,9 @@ struct mi_heap_s {
|
||||
mi_page_queue_t pages[MI_BIN_FULL + 1]; // queue of pages for each size class (or "bin")
|
||||
volatile _Atomic(mi_block_t*) thread_delayed_free;
|
||||
uintptr_t thread_id; // thread this heap belongs too
|
||||
uintptr_t cookie;
|
||||
uintptr_t random; // random number used for secure allocation
|
||||
uintptr_t cookie; // random cookie to verify pointers (see `_mi_ptr_cookie`)
|
||||
uintptr_t key[2]; // twb random keys used to encode the `thread_delayed_free` list
|
||||
mi_random_ctx_t random; // random number context used for secure allocation
|
||||
size_t page_count; // total number of pages in the `pages` queues.
|
||||
bool no_reclaim; // `true` if this heap should not reclaim abandoned pages
|
||||
};
|
||||
@ -384,22 +406,29 @@ void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount);
|
||||
#define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount)
|
||||
#define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount)
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Thread Local data
|
||||
// ------------------------------------------------------
|
||||
|
||||
typedef int64_t mi_msecs_t;
|
||||
|
||||
// Queue of segments
|
||||
typedef struct mi_segment_queue_s {
|
||||
mi_segment_t* first;
|
||||
mi_segment_t* last;
|
||||
} mi_segment_queue_t;
|
||||
|
||||
// OS thread local data
|
||||
typedef struct mi_os_tld_s {
|
||||
size_t region_idx; // start point for next allocation
|
||||
mi_stats_t* stats; // points to tld stats
|
||||
} mi_os_tld_t;
|
||||
|
||||
// Segments thread local data
|
||||
typedef struct mi_segments_tld_s {
|
||||
mi_segment_queue_t small_free; // queue of segments with free small pages
|
||||
mi_segment_queue_t medium_free; // queue of segments with free medium pages
|
||||
mi_page_queue_t pages_reset; // queue of freed pages that can be reset
|
||||
size_t count; // current number of segments;
|
||||
size_t peak_count; // peak number of segments
|
||||
size_t current_size; // current size of all segments
|
||||
@ -408,14 +437,9 @@ typedef struct mi_segments_tld_s {
|
||||
size_t cache_size; // total size of all segments in the cache
|
||||
mi_segment_t* cache; // (small) cache of segments
|
||||
mi_stats_t* stats; // points to tld stats
|
||||
mi_os_tld_t* os; // points to os stats
|
||||
} mi_segments_tld_t;
|
||||
|
||||
// OS thread local data
|
||||
typedef struct mi_os_tld_s {
|
||||
size_t region_idx; // start point for next allocation
|
||||
mi_stats_t* stats; // points to tld stats
|
||||
} mi_os_tld_t;
|
||||
|
||||
// Thread local data
|
||||
struct mi_tld_s {
|
||||
unsigned long long heartbeat; // monotonic heartbeat count
|
||||
|
@ -8,17 +8,17 @@ 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 120 // major + 2 digits minor
|
||||
#define MI_MALLOC_VERSION 150 // major + 2 digits minor
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Compiler specific attributes
|
||||
// ------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if (__GNUC__ <= 5) || (_MSC_VER <= 1900)
|
||||
#define mi_attr_noexcept throw()
|
||||
#else
|
||||
#if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11
|
||||
#define mi_attr_noexcept noexcept
|
||||
#else
|
||||
#define mi_attr_noexcept throw()
|
||||
#endif
|
||||
#else
|
||||
#define mi_attr_noexcept
|
||||
@ -37,32 +37,37 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#else
|
||||
#define mi_decl_allocator __declspec(restrict)
|
||||
#endif
|
||||
#define mi_decl_thread __declspec(thread)
|
||||
#define mi_cdecl __cdecl
|
||||
#define mi_attr_malloc
|
||||
#define mi_attr_alloc_size(s)
|
||||
#define mi_attr_alloc_size2(s1,s2)
|
||||
#define mi_cdecl __cdecl
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define mi_decl_thread __thread
|
||||
#define mi_attr_alloc_align(p)
|
||||
#elif defined(__GNUC__) // includes clang and icc
|
||||
#define mi_cdecl // leads to warnings... __attribute__((cdecl))
|
||||
#define mi_decl_export __attribute__((visibility("default")))
|
||||
#define mi_decl_allocator
|
||||
#define mi_attr_malloc __attribute__((malloc))
|
||||
#if defined(__clang_major__) && (__clang_major__ < 4)
|
||||
#if (defined(__clang_major__) && (__clang_major__ < 4)) || (__GNUC__ < 5)
|
||||
#define mi_attr_alloc_size(s)
|
||||
#define mi_attr_alloc_size2(s1,s2)
|
||||
#define mi_attr_alloc_align(p)
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
#define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))
|
||||
#define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))
|
||||
#define mi_attr_alloc_align(p)
|
||||
#else
|
||||
#define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))
|
||||
#define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))
|
||||
#define mi_attr_alloc_align(p) __attribute__((alloc_align(p)))
|
||||
#endif
|
||||
#define mi_cdecl // leads to warnings... __attribute__((cdecl))
|
||||
#else
|
||||
#define mi_decl_thread __thread
|
||||
#define mi_cdecl
|
||||
#define mi_decl_export
|
||||
#define mi_decl_allocator
|
||||
#define mi_attr_malloc
|
||||
#define mi_attr_alloc_size(s)
|
||||
#define mi_attr_alloc_size2(s1,s2)
|
||||
#define mi_cdecl
|
||||
#define mi_attr_alloc_align(p)
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------
|
||||
@ -104,26 +109,34 @@ mi_decl_export mi_decl_allocator void* mi_mallocn(size_t count, size_t size)
|
||||
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;
|
||||
|
||||
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;
|
||||
// ------------------------------------------------------
|
||||
// Internals
|
||||
// ------------------------------------------------------
|
||||
|
||||
typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
|
||||
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;
|
||||
|
||||
typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);
|
||||
mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;
|
||||
|
||||
typedef void (mi_cdecl mi_error_fun)(int err, void* arg);
|
||||
mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);
|
||||
|
||||
mi_decl_export void mi_collect(bool force) 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 void mi_stats_print(mi_output_fun* out) mi_attr_noexcept;
|
||||
mi_decl_export void mi_stats_print(void* out) mi_attr_noexcept; // backward compatibility: `out` is ignored and should be NULL
|
||||
mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) 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(mi_output_fun* out) mi_attr_noexcept;
|
||||
mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
@ -132,19 +145,19 @@ mi_decl_export void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept;
|
||||
// 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(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
|
||||
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);
|
||||
mi_decl_export mi_decl_allocator void* mi_zalloc_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_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
|
||||
mi_decl_export mi_decl_allocator void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export mi_decl_allocator void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2);
|
||||
mi_decl_export mi_decl_allocator void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2) mi_attr_alloc_align(3);
|
||||
mi_decl_export mi_decl_allocator void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2);
|
||||
mi_decl_export mi_decl_allocator void* mi_realloc_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_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);
|
||||
mi_decl_export mi_decl_allocator void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Heaps
|
||||
// ------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Heaps: first-class, but can only allocate from the same thread that created it.
|
||||
// -------------------------------------------------------------------------------------
|
||||
struct mi_heap_s;
|
||||
typedef struct mi_heap_s mi_heap_t;
|
||||
|
||||
@ -170,13 +183,13 @@ mi_decl_export char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noex
|
||||
mi_decl_export char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept;
|
||||
mi_decl_export char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept;
|
||||
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);
|
||||
mi_decl_export 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 mi_attr_malloc mi_attr_alloc_size(2);
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);
|
||||
mi_decl_export 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 mi_attr_malloc mi_attr_alloc_size(2);
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, 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_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3) mi_attr_alloc_align(4);
|
||||
mi_decl_export 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 mi_attr_malloc mi_attr_alloc_size2(2, 3);
|
||||
mi_decl_export mi_decl_allocator void* mi_heap_realloc_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_realloc_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_attr_alloc_align(4);
|
||||
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);
|
||||
|
||||
|
||||
@ -190,17 +203,17 @@ mi_decl_export mi_decl_allocator void* mi_heap_realloc_aligned_at(mi_heap_t* hea
|
||||
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(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3);
|
||||
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(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3) mi_attr_alloc_align(4);
|
||||
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(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(3) mi_attr_alloc_align(4);
|
||||
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(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_attr_alloc_align(5);
|
||||
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);
|
||||
|
||||
|
||||
@ -228,9 +241,14 @@ 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, size_t* pages_reserved) mi_attr_noexcept;
|
||||
mi_decl_export bool mi_is_redirected() mi_attr_noexcept;
|
||||
|
||||
mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept;
|
||||
mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept;
|
||||
|
||||
// deprecated
|
||||
mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept;
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Convenience
|
||||
// ------------------------------------------------------
|
||||
@ -262,17 +280,20 @@ typedef enum mi_option_e {
|
||||
// the following options are experimental
|
||||
mi_option_eager_commit,
|
||||
mi_option_eager_region_commit,
|
||||
mi_option_reset_decommits,
|
||||
mi_option_large_os_pages, // implies eager commit
|
||||
mi_option_reserve_huge_os_pages,
|
||||
mi_option_segment_cache,
|
||||
mi_option_page_reset,
|
||||
mi_option_cache_reset,
|
||||
mi_option_reset_decommits,
|
||||
mi_option_eager_commit_delay,
|
||||
mi_option_abandoned_page_reset,
|
||||
mi_option_segment_reset,
|
||||
mi_option_eager_commit_delay,
|
||||
mi_option_reset_delay,
|
||||
mi_option_use_numa_nodes,
|
||||
mi_option_os_tag,
|
||||
mi_option_max_errors,
|
||||
_mi_option_last
|
||||
_mi_option_last,
|
||||
mi_option_eager_page_commit = mi_option_eager_commit
|
||||
} mi_option_t;
|
||||
|
||||
|
||||
@ -298,11 +319,11 @@ 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 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_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1);
|
||||
mi_decl_export void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
|
||||
|
||||
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_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1);
|
||||
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_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept;
|
||||
@ -317,14 +338,74 @@ mi_decl_export void mi_free_size(void* p, size_t size) mi_attr_noexcept;
|
||||
mi_decl_export void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept;
|
||||
mi_decl_export void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept;
|
||||
|
||||
mi_decl_export void* mi_new(size_t n) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export void* mi_new_aligned(size_t n, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export void* mi_new_nothrow(size_t n) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export void* mi_new_aligned_nothrow(size_t n, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
// The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`.
|
||||
// (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception).
|
||||
mi_decl_export void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export void* mi_new_aligned(size_t size, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
|
||||
mi_decl_export void* mi_new_nothrow(size_t size) mi_attr_malloc mi_attr_alloc_size(1);
|
||||
mi_decl_export void* mi_new_aligned_nothrow(size_t size, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
|
||||
mi_decl_export void* mi_new_n(size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(1, 2);
|
||||
mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_malloc mi_attr_alloc_size(2);
|
||||
mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Implement the C++ std::allocator interface for use in STL containers.
|
||||
// (note: see `mimalloc-new-delete.h` for overriding the new/delete operators globally)
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <limits> // std::numeric_limits<ptrdiff_t>
|
||||
#if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11
|
||||
#include <type_traits> // std::true_type
|
||||
#include <utility> // std::forward
|
||||
#endif
|
||||
|
||||
template<class T> struct mi_stl_allocator {
|
||||
typedef T value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const& const_reference;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type const* const_pointer;
|
||||
template <class U> struct rebind { typedef mi_stl_allocator<U> other; };
|
||||
|
||||
mi_stl_allocator() mi_attr_noexcept { }
|
||||
mi_stl_allocator(const mi_stl_allocator&) mi_attr_noexcept { }
|
||||
template<class U> mi_stl_allocator(const mi_stl_allocator<U>&) mi_attr_noexcept { }
|
||||
mi_stl_allocator select_on_container_copy_construction() const { return *this; }
|
||||
void deallocate(T* p, size_type) { mi_free(p); }
|
||||
|
||||
#if (__cplusplus >= 201703L) // C++17
|
||||
T* allocate(size_type count) { return static_cast<T*>(mi_new_n(count, sizeof(T))); }
|
||||
T* allocate(size_type count, const void*) { return allocate(count); }
|
||||
#else
|
||||
pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_new_n(count, sizeof(value_type))); }
|
||||
#endif
|
||||
|
||||
#if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using propagate_on_container_swap = std::true_type;
|
||||
using is_always_equal = std::true_type;
|
||||
template <class U, class ...Args> void construct(U* p, Args&& ...args) { ::new(p) U(std::forward<Args>(args)...); }
|
||||
template <class U> void destroy(U* p) mi_attr_noexcept { p->~U(); }
|
||||
#else
|
||||
void construct(pointer p, value_type const& val) { ::new(p) value_type(val); }
|
||||
void destroy(pointer p) { p->~value_type(); }
|
||||
#endif
|
||||
|
||||
size_type max_size() const mi_attr_noexcept { return (std::numeric_limits<difference_type>::max() / sizeof(value_type)); }
|
||||
pointer address(reference x) const { return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
};
|
||||
|
||||
template<class T1,class T2> bool operator==(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return true; }
|
||||
template<class T1,class T2> bool operator!=(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return false; }
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
||||
|
274
readme.md
274
readme.md
@ -10,15 +10,15 @@
|
||||
mimalloc (pronounced "me-malloc")
|
||||
is a general purpose allocator with excellent [performance](#performance) characteristics.
|
||||
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.
|
||||
[Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages.
|
||||
Latest release:`v1.4.0` (2020-01-22).
|
||||
|
||||
It is a drop-in replacement for `malloc` and can be used in other programs
|
||||
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
|
||||
```
|
||||
|
||||
Notable aspects of the design include:
|
||||
It also has an easy way to override the allocator in [Windows](#override_on_windows). Notable aspects of the design include:
|
||||
|
||||
- __small and consistent__: the library is about 6k LOC using simple and
|
||||
consistent data structures. This makes it very suitable
|
||||
@ -45,9 +45,10 @@ Notable aspects of the design include:
|
||||
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),
|
||||
_mimalloc_ outperforms 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.
|
||||
is that it does consistently well over a wide range of benchmarks. There is also good huge OS page
|
||||
support for larger server programs.
|
||||
|
||||
The [documentation](https://microsoft.github.io/mimalloc) gives a full overview of the API.
|
||||
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.
|
||||
@ -56,6 +57,11 @@ Enjoy!
|
||||
|
||||
### Releases
|
||||
|
||||
* 2020-01-22, `v1.4.0`: stable release 1.4: improved performance for delayed OS page reset,
|
||||
more eager concurrent free, addition of STL allocator, fixed potential memory leak.
|
||||
* 2020-01-15, `v1.3.0`: stable release 1.3: bug fixes, improved randomness and [stronger
|
||||
free list encoding](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) in secure mode.
|
||||
* 2019-12-22, `v1.2.2`: stable release 1.2: minor updates.
|
||||
* 2019-11-22, `v1.2.0`: stable release 1.2: bug fixes, improved secure mode (free list corruption checks, double free mitigation). Improved dynamic overriding on Windows.
|
||||
* 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.
|
||||
@ -127,7 +133,7 @@ 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)
|
||||
find_package(mimalloc 1.4 REQUIRED)
|
||||
```
|
||||
in your `CMakeLists.txt` to find a locally installed mimalloc. Then use either:
|
||||
```
|
||||
@ -141,7 +147,9 @@ to link with the static library. See `test\CMakeLists.txt` for an example.
|
||||
|
||||
For best performance in C++ programs, it is also recommended to override the
|
||||
global `new` and `delete` operators. For convience, mimalloc provides
|
||||
[mimalloc-new-delete.h](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project.
|
||||
[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project.
|
||||
In C++, mimalloc also provides the `mi_stl_allocator` struct which implements the `std::allocator`
|
||||
interface.
|
||||
|
||||
You can pass environment variables to print verbose messages (`MIMALLOC_VERBOSE=1`)
|
||||
and statistics (`MIMALLOC_SHOW_STATS=1`) (in the debug version):
|
||||
@ -182,7 +190,7 @@ malloc requested: 32.8 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.
|
||||
completely and redirect all calls to the _mimalloc_ library instead .
|
||||
|
||||
## Environment Options
|
||||
|
||||
@ -192,23 +200,35 @@ 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_PAGE_RESET=1`: reset (or purge) OS pages when not in use. This can reduce
|
||||
memory fragmentation in long running (server) programs. If performance is impacted,
|
||||
`MIMALLOC_RESET_DELAY=`<msecs> can be set higher (100ms by default) to make the page
|
||||
reset occur less frequently.
|
||||
- `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]). 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
|
||||
can have fragmented memory (for that reason, we generally recommend to use `MIMALLOC_RESERVE_HUGE_OS_PAGES` instead when possible).
|
||||
<!--
|
||||
- `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.
|
||||
turned off by default on Windows as it looks not good in the task manager. However, turning it on has no
|
||||
real drawbacks and may improve performance by a little.
|
||||
-->
|
||||
- `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
|
||||
startup and can give quite a (latency) 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.
|
||||
contiguous physical memory can take a long time when memory is fragmented (but reserving the huge pages is done at
|
||||
startup only once).
|
||||
Note that we usually need to explicitly enable huge OS pages (as on [Windows][windows-huge] and [Linux][linux-huge])). With huge OS pages, it may be beneficial to set the setting
|
||||
`MIMALLOC_EAGER_COMMIT_DELAY=N` (with usually `N` as 1) to delay the initial `N` segments
|
||||
of a thread to not allocate in the huge OS pages; this prevents threads that are short lived
|
||||
and allocate just a little to take up space in the huge OS page area (which cannot be reset).
|
||||
|
||||
[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
|
||||
|
||||
|
||||
# Overriding Malloc
|
||||
|
||||
Overriding the standard `malloc` can be done either _dynamically_ or _statically_.
|
||||
@ -217,7 +237,7 @@ Overriding the standard `malloc` can be done either _dynamically_ or _statically
|
||||
|
||||
This is the recommended way to override the standard malloc interface.
|
||||
|
||||
### Linux, BSD
|
||||
### Override on Linux, BSD
|
||||
|
||||
On these ELF-based systems we preload the mimalloc shared
|
||||
library so all calls to the standard `malloc` interface are
|
||||
@ -236,7 +256,7 @@ or run with the debug version to get detailed statistics:
|
||||
> env MIMALLOC_SHOW_STATS=1 LD_PRELOAD=/usr/lib/libmimalloc-debug.so myprogram
|
||||
```
|
||||
|
||||
### MacOS
|
||||
### Override on MacOS
|
||||
|
||||
On macOS we can also preload the mimalloc shared
|
||||
library so all calls to the standard `malloc` interface are
|
||||
@ -248,13 +268,13 @@ resolved to the _mimalloc_ library.
|
||||
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).
|
||||
|
||||
Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is actively worked on to fix this
|
||||
(see issue [`#50`](https://github.com/microsoft/mimalloc/issues/50)).
|
||||
Note: unfortunately, at this time, dynamic overriding on macOS seems broken but it is
|
||||
actively worked on to fix this (see issue [`#50`](https://github.com/microsoft/mimalloc/issues/50)).
|
||||
|
||||
### Windows
|
||||
### Override on Windows
|
||||
|
||||
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).
|
||||
<span id="override_on_windows">Overriding on Windows</span> is robust but requires that you 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 main `mimalloc-override.dll` at runtime (as it is a dependency).
|
||||
The redirection DLL ensures that all calls to the C runtime malloc API get redirected to
|
||||
@ -264,8 +284,8 @@ 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. For best performance on Windows with C++, it
|
||||
is highly recommended to also override the `new`/`delete` operations (as described
|
||||
in the introduction).
|
||||
is also recommended to also override the `new`/`delete` operations (by including
|
||||
[`mimalloc-new-delete.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) a single(!) source file in your project).
|
||||
|
||||
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 was successfully redirected.
|
||||
@ -297,68 +317,71 @@ under your control or otherwise mixing of pointers from different heaps may occu
|
||||
|
||||
# Performance
|
||||
|
||||
Last update: 2020-01-20
|
||||
|
||||
We tested _mimalloc_ against many other top allocators over a wide
|
||||
range of benchmarks, ranging from various real world programs to
|
||||
synthetic benchmarks that see how the allocator behaves under more
|
||||
extreme circumstances.
|
||||
extreme circumstances. In our benchmark suite, _mimalloc_ outperforms other leading
|
||||
allocators (_jemalloc_, _tcmalloc_, _Hoard_, etc), and has a similar memory footprint. A nice property is that it
|
||||
does consistently well over the wide range of benchmarks.
|
||||
|
||||
In our benchmarks, _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 the wide range of benchmarks.
|
||||
|
||||
Allocators are interesting as there exists no algorithm that is generally
|
||||
General memory allocators are interesting as there exists no algorithm that is
|
||||
optimal -- for a given allocator one can usually construct a workload
|
||||
where it does not do so well. The goal is thus to find an allocation
|
||||
strategy that performs well over a wide range of benchmarks without
|
||||
suffering from underperformance in less common situations (which is what
|
||||
the second half of our benchmark set tests for).
|
||||
suffering from (too much) underperformance in less common situations.
|
||||
|
||||
We show here only the results on an AMD EPYC system (Apr 2019) -- for
|
||||
specific details and further benchmarks we refer to the [technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action).
|
||||
As always, interpret these results with care since some benchmarks test synthetic
|
||||
or uncommon situations that may never apply to your workloads. For example, most
|
||||
allocators do not do well on `xmalloc-testN` but that includes the best
|
||||
industrial allocators like _jemalloc_ and _tcmalloc_ that are used in some of
|
||||
the world's largest systems (like Chrome or FreeBSD).
|
||||
|
||||
The benchmark suite is scripted and available separately
|
||||
We show here only an overview -- for
|
||||
more specific details and further benchmarks we refer to the
|
||||
[technical report](https://www.microsoft.com/en-us/research/publication/mimalloc-free-list-sharding-in-action).
|
||||
The benchmark suite is automated and available separately
|
||||
as [mimalloc-bench](https://github.com/daanx/mimalloc-bench).
|
||||
|
||||
|
||||
## Benchmark Results
|
||||
## Benchmark Results on 36-core Intel
|
||||
|
||||
Testing on a big Amazon EC2 instance ([r5a.4xlarge](https://aws.amazon.com/ec2/instance-types/))
|
||||
consisting of a 16-core AMD EPYC 7000 at 2.5GHz
|
||||
with 128GB ECC memory, running Ubuntu 18.04.1 with LibC 2.27 and GCC 7.3.0.
|
||||
The measured allocators are _mimalloc_ (mi),
|
||||
Google's [_tcmalloc_](https://github.com/gperftools/gperftools) (tc) used in Chrome,
|
||||
[_jemalloc_](https://github.com/jemalloc/jemalloc) (je) by Jason Evans used in Firefox and FreeBSD,
|
||||
[_snmalloc_](https://github.com/microsoft/snmalloc) (sn) by Liétar et al. \[8], [_rpmalloc_](https://github.com/rampantpixels/rpmalloc) (rp) by Mattias Jansson at Rampant Pixels,
|
||||
[_Hoard_](https://github.com/emeryberger/Hoard) by Emery Berger \[1],
|
||||
the system allocator (glibc) (based on _PtMalloc2_), and the Intel thread
|
||||
building blocks [allocator](https://github.com/intel/tbb) (tbb).
|
||||
Testing on a big Amazon EC2 compute instance
|
||||
([c5.18xlarge](https://aws.amazon.com/ec2/instance-types/#Compute_Optimized))
|
||||
consisting of a 72 processor Intel Xeon at 3GHz
|
||||
with 144GiB ECC memory, running Ubuntu 18.04.1 with LibC 2.27 and GCC 7.4.0.
|
||||
The measured allocators are _mimalloc_ (xmi, tag:v1.4.0, page reset enabled)
|
||||
and its secure build as _smi_,
|
||||
Google's [_tcmalloc_](https://github.com/gperftools/gperftools) (tc, tag:gperftools-2.7) used in Chrome,
|
||||
Facebook's [_jemalloc_](https://github.com/jemalloc/jemalloc) (je, tag:5.2.1) by Jason Evans used in Firefox and FreeBSD,
|
||||
the Intel thread building blocks [allocator](https://github.com/intel/tbb) (tbb, tag:2020),
|
||||
[rpmalloc](https://github.com/mjansson/rpmalloc) (rp,tag:1.4.0) by Mattias Jansson,
|
||||
the original scalable [_Hoard_](https://github.com/emeryberger/Hoard) (tag:3.13) allocator by Emery Berger \[1],
|
||||
the memory compacting [_Mesh_](https://github.com/plasma-umass/Mesh) (git:51222e7) allocator by
|
||||
Bobby Powers _et al_ \[8],
|
||||
and finally the default system allocator (glibc, 2.7.0) (based on _PtMalloc2_).
|
||||
|
||||
![bench-r5a-1](doc/bench-r5a-1.svg)
|
||||
![bench-r5a-2](doc/bench-r5a-2.svg)
|
||||
<img width="90%" src="doc/bench-c5-18xlarge-2020-01-20-a.svg"/>
|
||||
<img width="90%" src="doc/bench-c5-18xlarge-2020-01-20-b.svg"/>
|
||||
|
||||
Memory usage:
|
||||
Any benchmarks ending in `N` run on all processors in parallel.
|
||||
Results are averaged over 10 runs and reported relative
|
||||
to mimalloc (where 1.2 means it took 1.2× longer to run).
|
||||
The legend also contains the _overall relative score_ between the
|
||||
allocators where 100 points is the maximum if an allocator is fastest on
|
||||
all benchmarks.
|
||||
|
||||
![bench-r5a-rss-1](doc/bench-r5a-rss-1.svg)
|
||||
![bench-r5a-rss-1](doc/bench-r5a-rss-2.svg)
|
||||
The single threaded _cfrac_ benchmark by Dave Barrett is an implementation of
|
||||
continued fraction factorization which uses many small short-lived allocations.
|
||||
All allocators do well on such common usage, where _mimalloc_ is just a tad
|
||||
faster than _tcmalloc_ and
|
||||
_jemalloc_.
|
||||
|
||||
(note: the _xmalloc-testN_ memory usage should be disregarded as it
|
||||
allocates more the faster the program runs).
|
||||
|
||||
In the first five benchmarks we can see _mimalloc_ outperforms the other
|
||||
allocators moderately, but we also see that all these modern allocators
|
||||
perform well -- the times of large performance differences in regular
|
||||
workloads are over :-).
|
||||
In _cfrac_ and _espresso_, _mimalloc_ is a tad faster than _tcmalloc_ and
|
||||
_jemalloc_, but a solid 10\% faster than all other allocators on
|
||||
_espresso_. The _tbb_ allocator does not do so well here and lags more than
|
||||
20\% behind _mimalloc_. The _cfrac_ and _espresso_ programs do not use much
|
||||
memory (~1.5MB) so it does not matter too much, but still _mimalloc_ uses
|
||||
about half the resident memory of _tcmalloc_.
|
||||
|
||||
The _leanN_ program is most interesting as a large realistic and
|
||||
concurrent workload of the [Lean](https://github.com/leanprover/lean) theorem prover
|
||||
compiling its own standard library, and there is a 8% speedup over _tcmalloc_. This is
|
||||
The _leanN_ program is interesting as a large realistic and
|
||||
concurrent workload of the [Lean](https://github.com/leanprover/lean)
|
||||
theorem prover compiling its own standard library, and there is a 7%
|
||||
speedup over _tcmalloc_. This is
|
||||
quite significant: if Lean spends 20% of its time in the
|
||||
allocator that means that _mimalloc_ is 1.3× faster than _tcmalloc_
|
||||
here. (This is surprising as that is not measured in a pure
|
||||
@ -367,19 +390,23 @@ outsized improvement here because _mimalloc_ has better locality in
|
||||
the allocation which improves performance for the *other* computations
|
||||
in a program as well).
|
||||
|
||||
The _redis_ benchmark shows more differences between the allocators where
|
||||
_mimalloc_ is 14\% faster than _jemalloc_. On this benchmark _tbb_ (and _Hoard_) do
|
||||
not do well and are over 40\% slower.
|
||||
The single threaded _redis_ benchmark again show that most allocators do well on such workloads where _tcmalloc_
|
||||
did best this time.
|
||||
|
||||
The _larson_ server workload allocates and frees objects between
|
||||
many threads. Larson and Krishnan \[2] observe this
|
||||
behavior (which they call _bleeding_) in actual server applications, and the
|
||||
benchmark simulates this.
|
||||
Here, _mimalloc_ is more than 2.5× faster than _tcmalloc_ and _jemalloc_
|
||||
due to the object migration between different threads. This is a difficult
|
||||
benchmark for other allocators too where _mimalloc_ is still 48% faster than the next
|
||||
fastest (_snmalloc_).
|
||||
The _larsonN_ server benchmark by Larson and Krishnan \[2] allocates and frees between threads. They observed this
|
||||
behavior (which they call _bleeding_) in actual server applications, and the benchmark simulates this.
|
||||
Here, _mimalloc_ is quite a bit faster than _tcmalloc_ and _jemalloc_ probably due to the object migration between different threads.
|
||||
|
||||
The _mstressN_ workload performs many allocations and re-allocations,
|
||||
and migrates objects between threads (as in _larsonN_). However, it also
|
||||
creates and destroys the _N_ worker threads a few times keeping some objects
|
||||
alive beyond the life time of the allocating thread. We observed this
|
||||
behavior in many larger server applications.
|
||||
|
||||
The [_rptestN_](https://github.com/mjansson/rpmalloc-benchmark) benchmark
|
||||
by Mattias Jansson is a allocator test originally designed
|
||||
for _rpmalloc_, and tries to simulate realistic allocation patterns over
|
||||
multiple threads. Here the differences between allocators become more apparent.
|
||||
|
||||
The second benchmark set tests specific aspects of the allocators and
|
||||
shows even more extreme differences between them.
|
||||
@ -388,46 +415,62 @@ The _alloc-test_, by
|
||||
[OLogN Technologies AG](http://ithare.com/testing-memory-allocators-ptmalloc2-tcmalloc-hoard-jemalloc-while-trying-to-simulate-real-world-loads/), is a very allocation intensive benchmark doing millions of
|
||||
allocations in various size classes. The test is scaled such that when an
|
||||
allocator performs almost identically on _alloc-test1_ as _alloc-testN_ it
|
||||
means that it scales linearly. Here, _tcmalloc_, _snmalloc_, and
|
||||
_Hoard_ seem to scale less well and do more than 10% worse on the
|
||||
multi-core version. Even the best allocators (_tcmalloc_ and _jemalloc_) are
|
||||
more than 10% slower as _mimalloc_ here.
|
||||
means that it scales linearly. Here, _tcmalloc_, and
|
||||
_Hoard_ seem to scale less well and do more than 10% worse on the multi-core version. Even the best industrial
|
||||
allocators (_tcmalloc_, _jemalloc_, and _tbb_) are more than 10% slower as _mimalloc_ here.
|
||||
|
||||
The _sh6bench_ and _sh8bench_ benchmarks are
|
||||
developed by [MicroQuill](http://www.microquill.com/) as part of SmartHeap.
|
||||
In _sh6bench_ _mimalloc_ does much
|
||||
better than the others (more than 2× faster than _jemalloc_).
|
||||
better than the others (more than 1.5× faster than _jemalloc_).
|
||||
We cannot explain this well but believe it is
|
||||
caused in part by the "reverse" free-ing pattern in _sh6bench_.
|
||||
Again in _sh8bench_ the _mimalloc_ allocator handles object migration
|
||||
between threads much better and is over 36% faster than the next best
|
||||
allocator, _snmalloc_. Whereas _tcmalloc_ did well on _sh6bench_, the
|
||||
addition of object migration caused it to be almost 3 times slower
|
||||
than before.
|
||||
The _sh8bench_ is a variation with object migration
|
||||
between threads; whereas _tcmalloc_ did well on _sh6bench_, the addition of object migration causes it to be 10× slower than before.
|
||||
|
||||
The _xmalloc-testN_ benchmark by Lever and Boreham \[5] and Christian Eder,
|
||||
simulates an asymmetric workload where
|
||||
some threads only allocate, and others only free. The _snmalloc_
|
||||
allocator was especially developed to handle this case well as it
|
||||
often occurs in concurrent message passing systems (like the [Pony] language
|
||||
for which _snmalloc_ was initially developed). Here we see that
|
||||
The _xmalloc-testN_ benchmark by Lever and Boreham \[5] and Christian Eder, simulates an asymmetric workload where
|
||||
some threads only allocate, and others only free -- they observed this pattern in
|
||||
larger server applications. Here we see that
|
||||
the _mimalloc_ technique of having non-contended sharded thread free
|
||||
lists pays off as it even outperforms _snmalloc_ here.
|
||||
Only _jemalloc_ also handles this reasonably well, while the
|
||||
others underperform by a large margin.
|
||||
lists pays off as it outperforms others by a very large margin. Only _rpmalloc_ and _tbb_ also scale well on this benchmark.
|
||||
|
||||
The _cache-scratch_ benchmark by Emery Berger \[1], and introduced with the Hoard
|
||||
allocator to test for _passive-false_ sharing of cache lines. With a single thread they all
|
||||
The _cache-scratch_ benchmark by Emery Berger \[1], and introduced with
|
||||
the Hoard allocator to test for _passive-false_ sharing of cache lines.
|
||||
With a single thread they all
|
||||
perform the same, but when running with multiple threads the potential allocator
|
||||
induced false sharing of the cache lines causes large run-time
|
||||
differences, where _mimalloc_ is more than 18× faster than _jemalloc_ and
|
||||
_tcmalloc_! Crundal \[6] describes in detail why the false cache line
|
||||
sharing occurs in the _tcmalloc_ design, and also discusses how this
|
||||
induced false sharing of the cache lines can cause large run-time differences.
|
||||
Crundal \[6] describes in detail why the false cache line sharing occurs in the _tcmalloc_ design, and also discusses how this
|
||||
can be avoided with some small implementation changes.
|
||||
Only _snmalloc_ and _tbb_ also avoid the
|
||||
cache line sharing like _mimalloc_. Kukanov and Voss \[7] describe in detail
|
||||
Only the _tbb_, _rpmalloc_ and _mesh_ allocators also avoid the
|
||||
cache line sharing completely, while _Hoard_ and _glibc_ seem to mitigate
|
||||
the effects. Kukanov and Voss \[7] describe in detail
|
||||
how the design of _tbb_ avoids the false cache line sharing.
|
||||
|
||||
## On 24-core AMD Epyc
|
||||
|
||||
For completeness, here are the results on a
|
||||
[r5a.12xlarge](https://aws.amazon.com/ec2/instance-types/#Memory_Optimized) instance
|
||||
having a 48 processor AMD Epyc 7000 at 2.5GHz with 384GiB of memory.
|
||||
The results are similar to the Intel results but it is interesting to
|
||||
see the differences in the _larsonN_, _mstressN_, and _xmalloc-testN_ benchmarks.
|
||||
|
||||
<img width="90%" src="doc/bench-r5a-12xlarge-2020-01-16-a.svg"/>
|
||||
<img width="90%" src="doc/bench-r5a-12xlarge-2020-01-16-b.svg"/>
|
||||
|
||||
|
||||
## Peak Working Set
|
||||
|
||||
The following figure shows the peak working set (rss) of the allocators
|
||||
on the benchmarks (on the c5.18xlarge instance).
|
||||
|
||||
<img width="90%" src="doc/bench-c5-18xlarge-2020-01-20-rss-a.svg"/>
|
||||
<img width="90%" src="doc/bench-c5-18xlarge-2020-01-20-rss-b.svg"/>
|
||||
|
||||
Note that the _xmalloc-testN_ memory usage should be disregarded as it
|
||||
allocates more the faster the program runs. Similarly, memory usage of
|
||||
_mstressN_, _rptestN_ and _sh8bench_ can vary depending on scheduling and
|
||||
speed. Nevertheless, even though _mimalloc_ is fast on these benchmarks we
|
||||
believe the memory usage is too high and hope to improve.
|
||||
|
||||
|
||||
# References
|
||||
@ -437,14 +480,12 @@ how the design of _tbb_ avoids the false cache line sharing.
|
||||
the Ninth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS-IX). Cambridge, MA, November 2000.
|
||||
[pdf](http://www.cs.utexas.edu/users/mckinley/papers/asplos-2000.pdf)
|
||||
|
||||
|
||||
- \[2] P. Larson and M. Krishnan. _Memory allocation for long-running server applications_. In ISMM, Vancouver, B.C., Canada, 1998.
|
||||
[pdf](http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=5F0BFB4F57832AEB6C11BF8257271088?doi=10.1.1.45.1947&rep=rep1&type=pdf)
|
||||
- \[2] P. Larson and M. Krishnan. _Memory allocation for long-running server applications_.
|
||||
In ISMM, Vancouver, B.C., Canada, 1998. [pdf](http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.45.1947&rep=rep1&type=pdf)
|
||||
|
||||
- \[3] D. Grunwald, B. Zorn, and R. Henderson.
|
||||
_Improving the cache locality of memory allocation_. In R. Cartwright, editor,
|
||||
Proceedings of the Conference on Programming Language Design and Implementation, pages 177–186, New York, NY, USA, June 1993.
|
||||
[pdf](http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.43.6621&rep=rep1&type=pdf)
|
||||
Proceedings of the Conference on Programming Language Design and Implementation, pages 177–186, New York, NY, USA, June 1993. [pdf](http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.43.6621&rep=rep1&type=pdf)
|
||||
|
||||
- \[4] J. Barnes and P. Hut. _A hierarchical O(n*log(n)) force-calculation algorithm_. Nature, 324:446-449, 1986.
|
||||
|
||||
@ -452,17 +493,22 @@ how the design of _tbb_ avoids the false cache line sharing.
|
||||
In USENIX Annual Technical Conference, Freenix Session. San Diego, CA. Jun. 2000.
|
||||
Available at <https://github.com/kuszmaul/SuperMalloc/tree/master/tests>
|
||||
|
||||
- \[6] Timothy Crundal. _Reducing Active-False Sharing in TCMalloc._
|
||||
2016. <http://courses.cecs.anu.edu.au/courses/CSPROJECTS/16S1/Reports/Timothy_Crundal_Report.pdf>. CS16S1 project at the Australian National University.
|
||||
- \[6] Timothy Crundal. _Reducing Active-False Sharing in TCMalloc_. 2016. CS16S1 project at the Australian National University. [pdf](http://courses.cecs.anu.edu.au/courses/CSPROJECTS/16S1/Reports/Timothy_Crundal_Report.pdf)
|
||||
|
||||
- \[7] Alexey Kukanov, and Michael J Voss.
|
||||
_The Foundations for Scalable Multi-Core Software in Intel Threading Building Blocks._
|
||||
Intel Technology Journal 11 (4). 2007
|
||||
|
||||
- \[8] Paul Liétar, Theodore Butler, Sylvan Clebsch, Sophia Drossopoulou, Juliana Franco, Matthew J Parkinson,
|
||||
- \[8] Bobby Powers, David Tench, Emery D. Berger, and Andrew McGregor.
|
||||
_Mesh: Compacting Memory Management for C/C++_
|
||||
In Proceedings of the 40th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI'19), June 2019, pages 333-–346.
|
||||
|
||||
<!--
|
||||
- \[9] Paul Liétar, Theodore Butler, Sylvan Clebsch, Sophia Drossopoulou, Juliana Franco, Matthew J Parkinson,
|
||||
Alex Shamis, Christoph M Wintersteiger, and David Chisnall.
|
||||
_Snmalloc: A Message Passing Allocator._
|
||||
In Proceedings of the 2019 ACM SIGPLAN International Symposium on Memory Management, 122–135. ACM. 2019.
|
||||
-->
|
||||
|
||||
|
||||
# Contributing
|
||||
|
@ -79,7 +79,7 @@ mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, siz
|
||||
|
||||
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;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_zalloc_aligned_at(heap, total, alignment, offset);
|
||||
}
|
||||
|
||||
@ -168,13 +168,13 @@ mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_
|
||||
|
||||
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;
|
||||
if (mi_count_size_overflow(newcount, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset);
|
||||
}
|
||||
|
||||
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;
|
||||
if (mi_count_size_overflow(newcount, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc_aligned(heap, p, total, alignment);
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
void operator delete[](void* p, std::size_t n) MI_FORWARD02(mi_free_size,p,n);
|
||||
#endif
|
||||
|
||||
#if (__cplusplus > 201402L || defined(__cpp_aligned_new))
|
||||
#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) && (!defined(__GNUC__) || (__GNUC__ > 5))
|
||||
void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
|
||||
void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
|
||||
void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); };
|
||||
|
271
src/alloc.c
271
src/alloc.c
@ -21,8 +21,8 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
|
||||
// Fast allocation in a page: just pop from the free list.
|
||||
// Fall back to generic allocation only if the list is empty.
|
||||
extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept {
|
||||
mi_assert_internal(page->block_size==0||page->block_size >= size);
|
||||
extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t size) mi_attr_noexcept {
|
||||
mi_assert_internal(page->xblock_size==0||mi_page_block_size(page) >= size);
|
||||
mi_block_t* block = page->free;
|
||||
if (mi_unlikely(block == NULL)) {
|
||||
return _mi_malloc_generic(heap, size); // slow path
|
||||
@ -92,18 +92,18 @@ extern inline mi_decl_allocator void* mi_malloc(size_t size) mi_attr_noexcept {
|
||||
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);
|
||||
UNUSED_RELEASE(size);
|
||||
mi_assert_internal(p != NULL);
|
||||
mi_assert_internal(size > 0 && page->block_size >= size);
|
||||
mi_assert_internal(mi_page_block_size(page) >= size); // size can be zero
|
||||
mi_assert_internal(_mi_ptr_page(p)==page);
|
||||
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));
|
||||
mi_assert_expensive(mi_mem_is_zero(p, mi_page_block_size(page)));
|
||||
}
|
||||
else {
|
||||
// otherwise memset
|
||||
memset(p, 0, page->block_size);
|
||||
memset(p, 0, mi_page_block_size(page));
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept {
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Check for double free in secure and debug mode
|
||||
// Check for double free in secure and debug mode
|
||||
// This is somewhat expensive so only enabled for secure mode 4
|
||||
// ------------------------------------------------------
|
||||
|
||||
@ -139,32 +139,28 @@ static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, const mi_block_t* block, const mi_block_t* n) {
|
||||
size_t psize;
|
||||
uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize);
|
||||
if (n == NULL || ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize))) {
|
||||
// Suspicious: the decoded value is in the same page (or NULL).
|
||||
// Walk the free lists to verify positively if it is already freed
|
||||
if (mi_list_contains(page, page->free, block) ||
|
||||
mi_list_contains(page, page->local_free, block) ||
|
||||
mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), block))
|
||||
{
|
||||
_mi_fatal_error("double free detected of block %p with size %zu\n", block, page->block_size);
|
||||
return true;
|
||||
}
|
||||
static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, const mi_block_t* block) {
|
||||
// The decoded value is in the same page (or NULL).
|
||||
// Walk the free lists to verify positively if it is already freed
|
||||
if (mi_list_contains(page, page->free, block) ||
|
||||
mi_list_contains(page, page->local_free, block) ||
|
||||
mi_list_contains(page, mi_page_thread_free(page), block))
|
||||
{
|
||||
_mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) {
|
||||
mi_block_t* n = mi_block_nextx(page, block, page->cookie); // pretend it is freed, and get the decoded first field
|
||||
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer?
|
||||
(n==NULL || mi_is_in_same_segment(block, n))) // quick check: in same segment or NULL?
|
||||
{
|
||||
// Suspicous: decoded value in block is in the same segment (or NULL) -- maybe a double free?
|
||||
mi_block_t* n = mi_block_nextx(page, block, page->key[0], page->key[1]); // pretend it is freed, and get the decoded first field
|
||||
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer?
|
||||
(n==NULL || mi_is_in_same_page(block, n))) // quick check: in same page or NULL?
|
||||
{
|
||||
// Suspicous: decoded value a in block is in the same page (or NULL) -- maybe a double free?
|
||||
// (continue in separate function to improve code generation)
|
||||
return mi_check_is_double_freex(page, block, n);
|
||||
}
|
||||
return mi_check_is_double_freex(page, block);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
@ -180,44 +176,50 @@ static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block
|
||||
// Free
|
||||
// ------------------------------------------------------
|
||||
|
||||
// free huge block from another thread
|
||||
static mi_decl_noinline void mi_free_huge_block_mt(mi_segment_t* segment, mi_page_t* page, mi_block_t* block) {
|
||||
// huge page segments are always abandoned and can be freed immediately
|
||||
mi_assert_internal(segment->page_kind==MI_PAGE_HUGE);
|
||||
mi_assert_internal(segment == _mi_page_segment(page));
|
||||
mi_assert_internal(mi_atomic_read_relaxed(&segment->thread_id)==0);
|
||||
|
||||
// claim it and free
|
||||
mi_heap_t* heap = mi_get_default_heap();
|
||||
// paranoia: if this it the last reference, the cas should always succeed
|
||||
if (mi_atomic_cas_strong(&segment->thread_id, heap->thread_id, 0)) {
|
||||
mi_block_set_next(page, block, page->free);
|
||||
page->free = block;
|
||||
page->used--;
|
||||
page->is_zero = false;
|
||||
mi_assert(page->used == 0);
|
||||
mi_tld_t* tld = heap->tld;
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
if (bsize > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_decrease(&tld->stats.giant, bsize);
|
||||
}
|
||||
else {
|
||||
_mi_stat_decrease(&tld->stats.huge, bsize);
|
||||
}
|
||||
_mi_segment_page_free(page, true, &tld->segments);
|
||||
}
|
||||
}
|
||||
|
||||
// multi-threaded free
|
||||
static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* block)
|
||||
{
|
||||
mi_thread_free_t tfree;
|
||||
mi_thread_free_t tfreex;
|
||||
bool use_delayed;
|
||||
|
||||
// huge page segments are always abandoned and can be freed immediately
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
if (segment->page_kind==MI_PAGE_HUGE) {
|
||||
// huge page segments are always abandoned and can be freed immediately
|
||||
mi_assert_internal(mi_atomic_read_relaxed(&segment->thread_id)==0);
|
||||
mi_assert_internal(mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&segment->abandoned_next))==NULL);
|
||||
// claim it and free
|
||||
mi_heap_t* heap = mi_get_default_heap();
|
||||
// paranoia: if this it the last reference, the cas should always succeed
|
||||
if (mi_atomic_cas_strong(&segment->thread_id,heap->thread_id,0)) {
|
||||
mi_block_set_next(page, block, page->free);
|
||||
page->free = block;
|
||||
page->used--;
|
||||
page->is_zero = false;
|
||||
mi_assert(page->used == 0);
|
||||
mi_tld_t* tld = heap->tld;
|
||||
if (page->block_size > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_decrease(&tld->stats.giant, page->block_size);
|
||||
}
|
||||
else {
|
||||
_mi_stat_decrease(&tld->stats.huge, page->block_size);
|
||||
}
|
||||
_mi_segment_page_free(page,true,&tld->segments);
|
||||
}
|
||||
mi_free_huge_block_mt(segment, page, block);
|
||||
return;
|
||||
}
|
||||
|
||||
mi_thread_free_t tfree;
|
||||
mi_thread_free_t tfreex;
|
||||
bool use_delayed;
|
||||
do {
|
||||
tfree = page->thread_free;
|
||||
use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE ||
|
||||
(mi_tf_delayed(tfree) == MI_NO_DELAYED_FREE && page->used == mi_atomic_read_relaxed(&page->thread_freed)+1) // data-race but ok, just optimizes early release of the page
|
||||
);
|
||||
tfree = mi_atomic_read_relaxed(&page->xthread_free);
|
||||
use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE);
|
||||
if (mi_unlikely(use_delayed)) {
|
||||
// unlikely: this only happens on the first concurrent free in a page that is in the full list
|
||||
tfreex = mi_tf_set_delayed(tfree,MI_DELAYED_FREEING);
|
||||
@ -227,31 +229,27 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc
|
||||
mi_block_set_next(page, block, mi_tf_block(tfree));
|
||||
tfreex = mi_tf_set_block(tfree,block);
|
||||
}
|
||||
} while (!mi_atomic_cas_weak(mi_atomic_cast(uintptr_t,&page->thread_free), tfreex, tfree));
|
||||
} while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree));
|
||||
|
||||
if (mi_likely(!use_delayed)) {
|
||||
// increment the thread free count and return
|
||||
mi_atomic_increment(&page->thread_freed);
|
||||
}
|
||||
else {
|
||||
if (mi_unlikely(use_delayed)) {
|
||||
// racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`)
|
||||
mi_heap_t* heap = (mi_heap_t*)mi_atomic_read_ptr(mi_atomic_cast(void*, &page->heap));
|
||||
mi_heap_t* heap = mi_page_heap(page);
|
||||
mi_assert_internal(heap != NULL);
|
||||
if (heap != NULL) {
|
||||
// add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity)
|
||||
mi_block_t* dfree;
|
||||
do {
|
||||
dfree = (mi_block_t*)heap->thread_delayed_free;
|
||||
mi_block_set_nextx(heap,block,dfree, heap->cookie);
|
||||
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
||||
dfree = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free);
|
||||
mi_block_set_nextx(heap,block,dfree, heap->key[0], heap->key[1]);
|
||||
} while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, block, dfree));
|
||||
}
|
||||
|
||||
// and reset the MI_DELAYED_FREEING flag
|
||||
do {
|
||||
tfreex = tfree = page->thread_free;
|
||||
mi_assert_internal(mi_tf_delayed(tfree) == MI_NEVER_DELAYED_FREE || mi_tf_delayed(tfree) == MI_DELAYED_FREEING);
|
||||
if (mi_tf_delayed(tfree) != MI_NEVER_DELAYED_FREE) tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE);
|
||||
} while (!mi_atomic_cas_weak(mi_atomic_cast(uintptr_t,&page->thread_free), tfreex, tfree));
|
||||
tfreex = tfree = mi_atomic_read_relaxed(&page->xthread_free);
|
||||
mi_assert_internal(mi_tf_delayed(tfree) == MI_DELAYED_FREEING);
|
||||
tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE);
|
||||
} while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree));
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,13 +258,13 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc
|
||||
static inline void _mi_free_block(mi_page_t* page, bool local, mi_block_t* block)
|
||||
{
|
||||
#if (MI_DEBUG)
|
||||
memset(block, MI_DEBUG_FREED, page->block_size);
|
||||
memset(block, MI_DEBUG_FREED, mi_page_block_size(page));
|
||||
#endif
|
||||
|
||||
// and push it on the free list
|
||||
if (mi_likely(local)) {
|
||||
// owning thread can free a block directly
|
||||
if (mi_check_is_double_free(page, block)) return;
|
||||
if (mi_unlikely(mi_check_is_double_free(page, block))) return;
|
||||
mi_block_set_next(page, block, page->local_free);
|
||||
page->local_free = block;
|
||||
page->used--;
|
||||
@ -287,12 +285,13 @@ static inline void _mi_free_block(mi_page_t* page, bool local, mi_block_t* block
|
||||
mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p) {
|
||||
mi_assert_internal(page!=NULL && p!=NULL);
|
||||
size_t diff = (uint8_t*)p - _mi_page_start(segment, page, NULL);
|
||||
size_t adjust = (diff % page->block_size);
|
||||
size_t adjust = (diff % mi_page_block_size(page));
|
||||
return (mi_block_t*)((uintptr_t)p - adjust);
|
||||
}
|
||||
|
||||
|
||||
static void mi_decl_noinline mi_free_generic(const mi_segment_t* segment, mi_page_t* page, bool local, void* p) {
|
||||
static void mi_decl_noinline mi_free_generic(const mi_segment_t* segment, bool local, void* p) {
|
||||
mi_page_t* page = _mi_segment_page_of(segment, p);
|
||||
mi_block_t* block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(segment, page, p) : (mi_block_t*)p);
|
||||
_mi_free_block(page, local, block);
|
||||
}
|
||||
@ -302,7 +301,7 @@ void mi_free(void* p) mi_attr_noexcept
|
||||
{
|
||||
#if (MI_DEBUG>0)
|
||||
if (mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0)) {
|
||||
_mi_error_message("trying to free an invalid (unaligned) pointer: %p\n", p);
|
||||
_mi_error_message(EINVAL, "trying to free an invalid (unaligned) pointer: %p\n", p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -312,16 +311,16 @@ void mi_free(void* p) mi_attr_noexcept
|
||||
|
||||
#if (MI_DEBUG!=0)
|
||||
if (mi_unlikely(!mi_is_in_heap_region(p))) {
|
||||
_mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: 0x%p\n"
|
||||
_mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: %p\n"
|
||||
"(this may still be a valid very large allocation (over 64MiB))\n", p);
|
||||
if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) {
|
||||
_mi_warning_message("(yes, the previous pointer 0x%p was valid after all)\n", p);
|
||||
_mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (MI_DEBUG!=0 || MI_SECURE>=4)
|
||||
if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) {
|
||||
_mi_error_message("trying to free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
_mi_error_message(EINVAL, "trying to free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -332,24 +331,27 @@ void mi_free(void* p) mi_attr_noexcept
|
||||
#if (MI_STAT>1)
|
||||
mi_heap_t* heap = mi_heap_get_default();
|
||||
mi_heap_stat_decrease(heap, malloc, mi_usable_size(p));
|
||||
if (page->block_size <= MI_LARGE_OBJ_SIZE_MAX) {
|
||||
mi_heap_stat_decrease(heap, normal[_mi_bin(page->block_size)], 1);
|
||||
if (page->xblock_size <= MI_LARGE_OBJ_SIZE_MAX) {
|
||||
mi_heap_stat_decrease(heap, normal[_mi_bin(page->xblock_size)], 1);
|
||||
}
|
||||
// huge page stat is accounted for in `_mi_page_retire`
|
||||
#endif
|
||||
|
||||
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;
|
||||
if (mi_check_is_double_free(page,block)) return;
|
||||
mi_block_t* const block = (mi_block_t*)p;
|
||||
if (mi_unlikely(mi_check_is_double_free(page,block))) return;
|
||||
mi_block_set_next(page, block, page->local_free);
|
||||
page->local_free = block;
|
||||
page->used--;
|
||||
if (mi_unlikely(mi_page_all_free(page))) { _mi_page_retire(page); }
|
||||
if (mi_unlikely(mi_page_all_free(page))) {
|
||||
_mi_page_retire(page);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// non-local, aligned blocks, or a full page; use the more generic path
|
||||
mi_free_generic(segment, page, tid == segment->thread_id, p);
|
||||
// note: recalc page in generic to improve code generation
|
||||
mi_free_generic(segment, tid == segment->thread_id, p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,13 +361,19 @@ bool _mi_free_delayed_block(mi_block_t* block) {
|
||||
mi_assert_internal(_mi_ptr_cookie(segment) == segment->cookie);
|
||||
mi_assert_internal(_mi_thread_id() == segment->thread_id);
|
||||
mi_page_t* page = _mi_segment_page_of(segment, block);
|
||||
if (mi_tf_delayed(page->thread_free) == MI_DELAYED_FREEING) {
|
||||
// we might already start delayed freeing while another thread has not yet
|
||||
// reset the delayed_freeing flag; in that case don't free it quite yet if
|
||||
// this is the last block remaining.
|
||||
if (page->used - page->thread_freed == 1) return false;
|
||||
}
|
||||
_mi_free_block(page,true,block);
|
||||
|
||||
// Clear the no-delayed flag so delayed freeing is used again for this page.
|
||||
// This must be done before collecting the free lists on this page -- otherwise
|
||||
// some blocks may end up in the page `thread_free` list with no blocks in the
|
||||
// heap `thread_delayed_free` list which may cause the page to be never freed!
|
||||
// (it would only be freed if we happen to scan it in `mi_page_queue_find_free_ex`)
|
||||
_mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, false /* dont overwrite never delayed */);
|
||||
|
||||
// collect all other non-local frees to ensure up-to-date `used` count
|
||||
_mi_page_free_collect(page, false);
|
||||
|
||||
// and free the block (possibly freeing the page as well since used is updated)
|
||||
_mi_free_block(page, true, block);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -374,7 +382,7 @@ size_t mi_usable_size(const void* p) mi_attr_noexcept {
|
||||
if (p==NULL) return 0;
|
||||
const mi_segment_t* segment = _mi_ptr_segment(p);
|
||||
const mi_page_t* page = _mi_segment_page_of(segment,p);
|
||||
size_t size = page->block_size;
|
||||
size_t size = mi_page_block_size(page);
|
||||
if (mi_unlikely(mi_page_has_aligned(page))) {
|
||||
ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)_mi_page_ptr_unalign(segment,page,p);
|
||||
mi_assert_internal(adjust >= 0 && (size_t)adjust <= size);
|
||||
@ -426,7 +434,7 @@ void mi_free_aligned(void* p, size_t alignment) 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;
|
||||
if (mi_count_size_overflow(count,size,&total)) return NULL;
|
||||
return mi_heap_zalloc(heap,total);
|
||||
}
|
||||
|
||||
@ -437,7 +445,7 @@ mi_decl_allocator void* mi_calloc(size_t count, size_t size) mi_attr_noexcept {
|
||||
// Uninitialized `calloc`
|
||||
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;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_malloc(heap, total);
|
||||
}
|
||||
|
||||
@ -478,7 +486,7 @@ mi_decl_allocator void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize
|
||||
|
||||
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;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_realloc(heap, p, total);
|
||||
}
|
||||
|
||||
@ -496,7 +504,7 @@ mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsiz
|
||||
|
||||
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;
|
||||
if (mi_count_size_overflow(count, size, &total)) return NULL;
|
||||
return mi_heap_rezalloc(heap, p, total);
|
||||
}
|
||||
|
||||
@ -564,7 +572,6 @@ char* mi_strndup(const char* s, size_t n) mi_attr_noexcept {
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
|
||||
// todo: use GetFullPathNameW to allow longer file names
|
||||
char buf[PATH_MAX];
|
||||
@ -639,10 +646,6 @@ static bool mi_try_new_handler(bool nothrow) {
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <errno.h>
|
||||
#ifndef ENOMEM
|
||||
#define ENOMEM 12
|
||||
#endif
|
||||
typedef void (*std_new_handler_t)();
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__))
|
||||
@ -662,7 +665,7 @@ std_new_handler_t mi_get_new_handler() {
|
||||
static bool mi_try_new_handler(bool nothrow) {
|
||||
std_new_handler_t h = mi_get_new_handler();
|
||||
if (h==NULL) {
|
||||
if (!nothrow) exit(ENOMEM);
|
||||
if (!nothrow) exit(ENOMEM); // cannot throw in plain C, use exit as we are out of memory anyway.
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
@ -672,36 +675,70 @@ static bool mi_try_new_handler(bool nothrow) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static mi_decl_noinline void* mi_try_new(size_t n, bool nothrow ) {
|
||||
static mi_decl_noinline void* mi_try_new(size_t size, bool nothrow ) {
|
||||
void* p = NULL;
|
||||
while(p == NULL && mi_try_new_handler(nothrow)) {
|
||||
p = mi_malloc(n);
|
||||
p = mi_malloc(size);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void* mi_new(size_t n) {
|
||||
void* p = mi_malloc(n);
|
||||
if (mi_unlikely(p == NULL)) return mi_try_new(n,false);
|
||||
void* mi_new(size_t size) {
|
||||
void* p = mi_malloc(size);
|
||||
if (mi_unlikely(p == NULL)) return mi_try_new(size,false);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* mi_new_aligned(size_t n, size_t alignment) {
|
||||
void* mi_new_nothrow(size_t size) {
|
||||
void* p = mi_malloc(size);
|
||||
if (mi_unlikely(p == NULL)) return mi_try_new(size, true);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* mi_new_aligned(size_t size, size_t alignment) {
|
||||
void* p;
|
||||
do { p = mi_malloc_aligned(n, alignment); }
|
||||
do {
|
||||
p = mi_malloc_aligned(size, alignment);
|
||||
}
|
||||
while(p == NULL && mi_try_new_handler(false));
|
||||
return p;
|
||||
}
|
||||
|
||||
void* mi_new_nothrow(size_t n) {
|
||||
void* p = mi_malloc(n);
|
||||
if (mi_unlikely(p == NULL)) return mi_try_new(n,true);
|
||||
void* mi_new_aligned_nothrow(size_t size, size_t alignment) {
|
||||
void* p;
|
||||
do {
|
||||
p = mi_malloc_aligned(size, alignment);
|
||||
}
|
||||
while(p == NULL && mi_try_new_handler(true));
|
||||
return p;
|
||||
}
|
||||
|
||||
void* mi_new_aligned_nothrow(size_t n, size_t alignment) {
|
||||
void* p;
|
||||
do { p = mi_malloc_aligned(n, alignment); }
|
||||
while (p == NULL && mi_try_new_handler(true));
|
||||
return p;
|
||||
void* mi_new_n(size_t count, size_t size) {
|
||||
size_t total;
|
||||
if (mi_unlikely(mi_count_size_overflow(count, size, &total))) {
|
||||
mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return mi_new(total);
|
||||
}
|
||||
}
|
||||
|
||||
void* mi_new_realloc(void* p, size_t newsize) {
|
||||
void* q;
|
||||
do {
|
||||
q = mi_realloc(p, newsize);
|
||||
} while (q == NULL && mi_try_new_handler(false));
|
||||
return q;
|
||||
}
|
||||
|
||||
void* mi_new_reallocn(void* p, size_t newcount, size_t size) {
|
||||
size_t total;
|
||||
if (mi_unlikely(mi_count_size_overflow(newcount, size, &total))) {
|
||||
mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return mi_new_realloc(p, total);
|
||||
}
|
||||
}
|
||||
|
356
src/arena.c
Normal file
356
src/arena.c
Normal file
@ -0,0 +1,356 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 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.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
"Arenas" are fixed area's of OS memory from which we can allocate
|
||||
large blocks (>= MI_ARENA_BLOCK_SIZE, 32MiB).
|
||||
In contrast to the rest of mimalloc, the arenas are shared between
|
||||
threads and need to be accessed using atomic operations.
|
||||
|
||||
Currently arenas are only used to for huge OS page (1GiB) reservations,
|
||||
otherwise it delegates to direct allocation from the OS.
|
||||
In the future, we can expose an API to manually add more kinds of arenas
|
||||
which is sometimes needed for embedded devices or shared memory for example.
|
||||
(We can also employ this with WASI or `sbrk` systems to reserve large arenas
|
||||
on demand and be able to reuse them efficiently).
|
||||
|
||||
The arena allocation needs to be thread safe and we use an atomic
|
||||
bitmap to allocate. The current implementation of the bitmap can
|
||||
only do this within a field (`uintptr_t`) so we can allocate at most
|
||||
blocks of 2GiB (64*32MiB) and no object can cross the boundary. This
|
||||
can lead to fragmentation but fortunately most objects will be regions
|
||||
of 256MiB in practice.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc-internal.h"
|
||||
#include "mimalloc-atomic.h"
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
#include "bitmap.inc.c" // atomic bitmap
|
||||
|
||||
|
||||
// os.c
|
||||
void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool* large, mi_os_tld_t* tld);
|
||||
void _mi_os_free(void* p, size_t size, mi_stats_t* stats);
|
||||
|
||||
void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_secs, size_t* pages_reserved, size_t* psize);
|
||||
void _mi_os_free_huge_pages(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);
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Arena allocation
|
||||
----------------------------------------------------------- */
|
||||
|
||||
#define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE
|
||||
#define MI_ARENA_BLOCK_SIZE (8*MI_SEGMENT_ALIGN) // 32MiB
|
||||
#define MI_ARENA_MAX_OBJ_SIZE (MI_BITMAP_FIELD_BITS * MI_ARENA_BLOCK_SIZE) // 2GiB
|
||||
#define MI_ARENA_MIN_OBJ_SIZE (MI_ARENA_BLOCK_SIZE/2) // 16MiB
|
||||
#define MI_MAX_ARENAS (64) // not more than 256 (since we use 8 bits in the memid)
|
||||
|
||||
// A memory arena descriptor
|
||||
typedef struct mi_arena_s {
|
||||
_Atomic(uint8_t*) start; // the start of the memory area
|
||||
size_t block_count; // size of the area in arena blocks (of `MI_ARENA_BLOCK_SIZE`)
|
||||
size_t field_count; // number of bitmap fields (where `field_count * MI_BITMAP_FIELD_BITS >= block_count`)
|
||||
int numa_node; // associated NUMA node
|
||||
bool is_zero_init; // is the arena zero initialized?
|
||||
bool is_committed; // is the memory committed
|
||||
bool is_large; // large OS page allocated
|
||||
volatile _Atomic(uintptr_t) search_idx; // optimization to start the search for free blocks
|
||||
mi_bitmap_field_t* blocks_dirty; // are the blocks potentially non-zero?
|
||||
mi_bitmap_field_t* blocks_committed; // if `!is_committed`, are the blocks committed?
|
||||
mi_bitmap_field_t blocks_inuse[1]; // in-place bitmap of in-use blocks (of size `field_count`)
|
||||
} mi_arena_t;
|
||||
|
||||
|
||||
// The available arenas
|
||||
static mi_decl_cache_align _Atomic(mi_arena_t*) mi_arenas[MI_MAX_ARENAS];
|
||||
static mi_decl_cache_align _Atomic(uintptr_t) mi_arena_count; // = 0
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Arena allocations get a memory id where the lower 8 bits are
|
||||
the arena index +1, and the upper bits the block index.
|
||||
----------------------------------------------------------- */
|
||||
|
||||
// Use `0` as a special id for direct OS allocated memory.
|
||||
#define MI_MEMID_OS 0
|
||||
|
||||
static size_t mi_arena_id_create(size_t arena_index, mi_bitmap_index_t bitmap_index) {
|
||||
mi_assert_internal(arena_index < 0xFE);
|
||||
mi_assert_internal(((bitmap_index << 8) >> 8) == bitmap_index); // no overflow?
|
||||
return ((bitmap_index << 8) | ((arena_index+1) & 0xFF));
|
||||
}
|
||||
|
||||
static void mi_arena_id_indices(size_t memid, size_t* arena_index, mi_bitmap_index_t* bitmap_index) {
|
||||
mi_assert_internal(memid != MI_MEMID_OS);
|
||||
*arena_index = (memid & 0xFF) - 1;
|
||||
*bitmap_index = (memid >> 8);
|
||||
}
|
||||
|
||||
static size_t mi_block_count_of_size(size_t size) {
|
||||
return _mi_divide_up(size, MI_ARENA_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Thread safe allocation in an arena
|
||||
----------------------------------------------------------- */
|
||||
static bool mi_arena_alloc(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx)
|
||||
{
|
||||
const size_t fcount = arena->field_count;
|
||||
size_t idx = mi_atomic_read(&arena->search_idx); // start from last search
|
||||
for (size_t visited = 0; visited < fcount; visited++, idx++) {
|
||||
if (idx >= fcount) idx = 0; // wrap around
|
||||
// try to atomically claim a range of bits
|
||||
if (mi_bitmap_try_find_claim_field(arena->blocks_inuse, idx, blocks, bitmap_idx)) {
|
||||
mi_atomic_write(&arena->search_idx, idx); // start search from here next time
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Arena Allocation
|
||||
----------------------------------------------------------- */
|
||||
|
||||
static void* mi_arena_alloc_from(mi_arena_t* arena, size_t arena_index, size_t needed_bcount,
|
||||
bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld)
|
||||
{
|
||||
mi_bitmap_index_t bitmap_index;
|
||||
if (!mi_arena_alloc(arena, needed_bcount, &bitmap_index)) return NULL;
|
||||
|
||||
// claimed it! set the dirty bits (todo: no need for an atomic op here?)
|
||||
void* p = arena->start + (mi_bitmap_index_bit(bitmap_index)*MI_ARENA_BLOCK_SIZE);
|
||||
*memid = mi_arena_id_create(arena_index, bitmap_index);
|
||||
*is_zero = mi_bitmap_claim(arena->blocks_dirty, arena->field_count, needed_bcount, bitmap_index, NULL);
|
||||
*large = arena->is_large;
|
||||
if (arena->is_committed) {
|
||||
// always committed
|
||||
*commit = true;
|
||||
}
|
||||
else if (*commit) {
|
||||
// arena not committed as a whole, but commit requested: ensure commit now
|
||||
bool any_uncommitted;
|
||||
mi_bitmap_claim(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index, &any_uncommitted);
|
||||
if (any_uncommitted) {
|
||||
bool commit_zero;
|
||||
_mi_os_commit(p, needed_bcount * MI_ARENA_BLOCK_SIZE, &commit_zero, tld->stats);
|
||||
if (commit_zero) *is_zero = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no need to commit, but check if already fully committed
|
||||
*commit = mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, needed_bcount, bitmap_index);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void* _mi_arena_alloc_aligned(size_t size, size_t alignment,
|
||||
bool* commit, bool* large, bool* is_zero,
|
||||
size_t* memid, mi_os_tld_t* tld)
|
||||
{
|
||||
mi_assert_internal(commit != NULL && large != NULL && is_zero != NULL && memid != NULL && tld != NULL);
|
||||
mi_assert_internal(size > 0);
|
||||
*memid = MI_MEMID_OS;
|
||||
*is_zero = false;
|
||||
|
||||
// try to allocate in an arena if the alignment is small enough
|
||||
// and the object is not too large or too small.
|
||||
if (alignment <= MI_SEGMENT_ALIGN &&
|
||||
size <= MI_ARENA_MAX_OBJ_SIZE &&
|
||||
size >= MI_ARENA_MIN_OBJ_SIZE)
|
||||
{
|
||||
const size_t bcount = mi_block_count_of_size(size);
|
||||
const int numa_node = _mi_os_numa_node(tld); // current numa node
|
||||
|
||||
mi_assert_internal(size <= bcount*MI_ARENA_BLOCK_SIZE);
|
||||
// try numa affine allocation
|
||||
for (size_t i = 0; i < MI_MAX_ARENAS; i++) {
|
||||
mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t, &mi_arenas[i]);
|
||||
if (arena==NULL) break; // end reached
|
||||
if ((arena->numa_node<0 || arena->numa_node==numa_node) && // numa local?
|
||||
(*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages
|
||||
{
|
||||
void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_zero, memid, tld);
|
||||
mi_assert_internal((uintptr_t)p % alignment == 0);
|
||||
if (p != NULL) return p;
|
||||
}
|
||||
}
|
||||
// try from another numa node instead..
|
||||
for (size_t i = 0; i < MI_MAX_ARENAS; i++) {
|
||||
mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t, &mi_arenas[i]);
|
||||
if (arena==NULL) break; // end reached
|
||||
if ((arena->numa_node>=0 && arena->numa_node!=numa_node) && // not numa local!
|
||||
(*large || !arena->is_large)) // large OS pages allowed, or arena is not large OS pages
|
||||
{
|
||||
void* p = mi_arena_alloc_from(arena, i, bcount, commit, large, is_zero, memid, tld);
|
||||
mi_assert_internal((uintptr_t)p % alignment == 0);
|
||||
if (p != NULL) return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, fall back to the OS
|
||||
*is_zero = true;
|
||||
*memid = MI_MEMID_OS;
|
||||
return _mi_os_alloc_aligned(size, alignment, *commit, large, tld);
|
||||
}
|
||||
|
||||
void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld)
|
||||
{
|
||||
return _mi_arena_alloc_aligned(size, MI_ARENA_BLOCK_SIZE, commit, large, is_zero, memid, tld);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Arena free
|
||||
----------------------------------------------------------- */
|
||||
|
||||
void _mi_arena_free(void* p, size_t size, size_t memid, mi_stats_t* stats) {
|
||||
mi_assert_internal(size > 0 && stats != NULL);
|
||||
if (p==NULL) return;
|
||||
if (size==0) return;
|
||||
if (memid == MI_MEMID_OS) {
|
||||
// was a direct OS allocation, pass through
|
||||
_mi_os_free(p, size, stats);
|
||||
}
|
||||
else {
|
||||
// allocated in an arena
|
||||
size_t arena_idx;
|
||||
size_t bitmap_idx;
|
||||
mi_arena_id_indices(memid, &arena_idx, &bitmap_idx);
|
||||
mi_assert_internal(arena_idx < MI_MAX_ARENAS);
|
||||
mi_arena_t* arena = mi_atomic_read_ptr_relaxed(mi_arena_t,&mi_arenas[arena_idx]);
|
||||
mi_assert_internal(arena != NULL);
|
||||
if (arena == NULL) {
|
||||
_mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
return;
|
||||
}
|
||||
mi_assert_internal(arena->field_count > mi_bitmap_index_field(bitmap_idx));
|
||||
if (arena->field_count <= mi_bitmap_index_field(bitmap_idx)) {
|
||||
_mi_error_message(EINVAL, "trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
|
||||
return;
|
||||
}
|
||||
const size_t blocks = mi_block_count_of_size(size);
|
||||
bool ones = mi_bitmap_unclaim(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx);
|
||||
if (!ones) {
|
||||
_mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size);
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Add an arena.
|
||||
----------------------------------------------------------- */
|
||||
|
||||
static bool mi_arena_add(mi_arena_t* arena) {
|
||||
mi_assert_internal(arena != NULL);
|
||||
mi_assert_internal((uintptr_t)mi_atomic_read_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0);
|
||||
mi_assert_internal(arena->block_count > 0);
|
||||
|
||||
uintptr_t i = mi_atomic_increment(&mi_arena_count);
|
||||
if (i >= MI_MAX_ARENAS) {
|
||||
mi_atomic_decrement(&mi_arena_count);
|
||||
return false;
|
||||
}
|
||||
mi_atomic_write_ptr(mi_arena_t,&mi_arenas[i], arena);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Reserve a huge page arena.
|
||||
----------------------------------------------------------- */
|
||||
#include <errno.h> // ENOMEM
|
||||
|
||||
// reserve at a specific numa node
|
||||
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept {
|
||||
if (pages==0) return 0;
|
||||
if (numa_node < -1) numa_node = -1;
|
||||
if (numa_node >= 0) numa_node = numa_node % _mi_os_numa_node_count();
|
||||
size_t hsize = 0;
|
||||
size_t pages_reserved = 0;
|
||||
void* p = _mi_os_alloc_huge_os_pages(pages, numa_node, timeout_msecs, &pages_reserved, &hsize);
|
||||
if (p==NULL || pages_reserved==0) {
|
||||
_mi_warning_message("failed to reserve %zu gb huge pages\n", pages);
|
||||
return ENOMEM;
|
||||
}
|
||||
_mi_verbose_message("reserved %zu gb huge pages on numa node %i (of the %zu gb requested)\n", pages_reserved, numa_node, pages);
|
||||
|
||||
size_t bcount = mi_block_count_of_size(hsize);
|
||||
size_t fields = _mi_divide_up(bcount, MI_BITMAP_FIELD_BITS);
|
||||
size_t asize = sizeof(mi_arena_t) + (2*fields*sizeof(mi_bitmap_field_t));
|
||||
mi_arena_t* arena = (mi_arena_t*)_mi_os_alloc(asize, &_mi_stats_main); // TODO: can we avoid allocating from the OS?
|
||||
if (arena == NULL) {
|
||||
_mi_os_free_huge_pages(p, hsize, &_mi_stats_main);
|
||||
return ENOMEM;
|
||||
}
|
||||
arena->block_count = bcount;
|
||||
arena->field_count = fields;
|
||||
arena->start = (uint8_t*)p;
|
||||
arena->numa_node = numa_node; // TODO: or get the current numa node if -1? (now it allows anyone to allocate on -1)
|
||||
arena->is_large = true;
|
||||
arena->is_zero_init = true;
|
||||
arena->is_committed = true;
|
||||
arena->search_idx = 0;
|
||||
arena->blocks_dirty = &arena->blocks_inuse[fields]; // just after inuse bitmap
|
||||
arena->blocks_committed = NULL;
|
||||
// the bitmaps are already zero initialized due to os_alloc
|
||||
// just claim leftover blocks if needed
|
||||
ptrdiff_t post = (fields * MI_BITMAP_FIELD_BITS) - bcount;
|
||||
mi_assert_internal(post >= 0);
|
||||
if (post > 0) {
|
||||
// don't use leftover bits at the end
|
||||
mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post);
|
||||
mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL);
|
||||
}
|
||||
|
||||
mi_arena_add(arena);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// reserve huge pages evenly among the given number of numa nodes (or use the available ones as detected)
|
||||
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept {
|
||||
if (pages == 0) return 0;
|
||||
|
||||
// pages per numa node
|
||||
size_t numa_count = (numa_nodes > 0 ? numa_nodes : _mi_os_numa_node_count());
|
||||
if (numa_count <= 0) numa_count = 1;
|
||||
const size_t pages_per = pages / numa_count;
|
||||
const size_t pages_mod = pages % numa_count;
|
||||
const size_t timeout_per = (timeout_msecs==0 ? 0 : (timeout_msecs / numa_count) + 50);
|
||||
|
||||
// reserve evenly among numa nodes
|
||||
for (size_t numa_node = 0; numa_node < numa_count && pages > 0; numa_node++) {
|
||||
size_t node_pages = pages_per; // can be 0
|
||||
if (numa_node < pages_mod) node_pages++;
|
||||
int err = mi_reserve_huge_os_pages_at(node_pages, (int)numa_node, timeout_per);
|
||||
if (err) return err;
|
||||
if (pages < node_pages) {
|
||||
pages = 0;
|
||||
}
|
||||
else {
|
||||
pages -= node_pages;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept {
|
||||
UNUSED(max_secs);
|
||||
_mi_warning_message("mi_reserve_huge_os_pages is deprecated: use mi_reserve_huge_os_pages_interleave/at instead\n");
|
||||
if (pages_reserved != NULL) *pages_reserved = 0;
|
||||
int err = mi_reserve_huge_os_pages_interleave(pages, 0, (size_t)(max_secs * 1000.0));
|
||||
if (err==0 && pages_reserved!=NULL) *pages_reserved = pages;
|
||||
return err;
|
||||
}
|
240
src/bitmap.inc.c
Normal file
240
src/bitmap.inc.c
Normal file
@ -0,0 +1,240 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 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.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
This file is meant to be included in other files for efficiency.
|
||||
It implements a bitmap that can set/reset sequences of bits atomically
|
||||
and is used to concurrently claim memory ranges.
|
||||
|
||||
A bitmap is an array of fields where each field is a machine word (`uintptr_t`)
|
||||
|
||||
A current limitation is that the bit sequences cannot cross fields
|
||||
and that the sequence must be smaller or equal to the bits in a field.
|
||||
---------------------------------------------------------------------------- */
|
||||
#pragma once
|
||||
#ifndef MI_BITMAP_C
|
||||
#define MI_BITMAP_C
|
||||
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc-internal.h"
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Bitmap definition
|
||||
----------------------------------------------------------- */
|
||||
|
||||
#define MI_BITMAP_FIELD_BITS (8*MI_INTPTR_SIZE)
|
||||
#define MI_BITMAP_FIELD_FULL (~((uintptr_t)0)) // all bits set
|
||||
|
||||
// An atomic bitmap of `uintptr_t` fields
|
||||
typedef volatile _Atomic(uintptr_t) mi_bitmap_field_t;
|
||||
typedef mi_bitmap_field_t* mi_bitmap_t;
|
||||
|
||||
// A bitmap index is the index of the bit in a bitmap.
|
||||
typedef size_t mi_bitmap_index_t;
|
||||
|
||||
// Create a bit index.
|
||||
static inline mi_bitmap_index_t mi_bitmap_index_create(size_t idx, size_t bitidx) {
|
||||
mi_assert_internal(bitidx < MI_BITMAP_FIELD_BITS);
|
||||
return (idx*MI_BITMAP_FIELD_BITS) + bitidx;
|
||||
}
|
||||
|
||||
// Get the field index from a bit index.
|
||||
static inline size_t mi_bitmap_index_field(mi_bitmap_index_t bitmap_idx) {
|
||||
return (bitmap_idx / MI_BITMAP_FIELD_BITS);
|
||||
}
|
||||
|
||||
// Get the bit index in a bitmap field
|
||||
static inline size_t mi_bitmap_index_bit_in_field(mi_bitmap_index_t bitmap_idx) {
|
||||
return (bitmap_idx % MI_BITMAP_FIELD_BITS);
|
||||
}
|
||||
|
||||
// Get the full bit index
|
||||
static inline size_t mi_bitmap_index_bit(mi_bitmap_index_t bitmap_idx) {
|
||||
return bitmap_idx;
|
||||
}
|
||||
|
||||
|
||||
// The bit mask for a given number of blocks at a specified bit index.
|
||||
static inline uintptr_t mi_bitmap_mask_(size_t count, size_t bitidx) {
|
||||
mi_assert_internal(count + bitidx <= MI_BITMAP_FIELD_BITS);
|
||||
if (count == MI_BITMAP_FIELD_BITS) return MI_BITMAP_FIELD_FULL;
|
||||
return ((((uintptr_t)1 << count) - 1) << bitidx);
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Use bit scan forward/reverse to quickly find the first zero bit if it is available
|
||||
----------------------------------------------------------- */
|
||||
#if defined(_MSC_VER)
|
||||
#define MI_HAVE_BITSCAN
|
||||
#include <intrin.h>
|
||||
static inline size_t mi_bsf(uintptr_t x) {
|
||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
||||
DWORD idx;
|
||||
MI_64(_BitScanForward)(&idx, x);
|
||||
return idx;
|
||||
}
|
||||
static inline size_t mi_bsr(uintptr_t x) {
|
||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
||||
DWORD idx;
|
||||
MI_64(_BitScanReverse)(&idx, x);
|
||||
return idx;
|
||||
}
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#include <limits.h> // LONG_MAX
|
||||
#define MI_HAVE_BITSCAN
|
||||
#if (INTPTR_MAX == LONG_MAX)
|
||||
# define MI_L(x) x##l
|
||||
#else
|
||||
# define MI_L(x) x##ll
|
||||
#endif
|
||||
static inline size_t mi_bsf(uintptr_t x) {
|
||||
return (x==0 ? 8*MI_INTPTR_SIZE : MI_L(__builtin_ctz)(x));
|
||||
}
|
||||
static inline size_t mi_bsr(uintptr_t x) {
|
||||
return (x==0 ? 8*MI_INTPTR_SIZE : (8*MI_INTPTR_SIZE - 1) - MI_L(__builtin_clz)(x));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Claim a bit sequence atomically
|
||||
----------------------------------------------------------- */
|
||||
|
||||
// Try to atomically claim a sequence of `count` bits at in `idx`
|
||||
// in the bitmap field. Returns `true` on success.
|
||||
static inline bool mi_bitmap_try_claim_field(mi_bitmap_t bitmap, size_t bitmap_fields, const size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||
mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields);
|
||||
mi_assert_internal(bitidx + count <= MI_BITMAP_FIELD_BITS);
|
||||
|
||||
uintptr_t field = mi_atomic_read_relaxed(&bitmap[idx]);
|
||||
if ((field & mask) == 0) { // free?
|
||||
if (mi_atomic_cas_strong(&bitmap[idx], (field|mask), field)) {
|
||||
// claimed!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Try to atomically claim a sequence of `count` bits in a single
|
||||
// field at `idx` in `bitmap`. Returns `true` on success.
|
||||
static inline bool mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx)
|
||||
{
|
||||
mi_assert_internal(bitmap_idx != NULL);
|
||||
volatile _Atomic(uintptr_t)* field = &bitmap[idx];
|
||||
uintptr_t map = mi_atomic_read(field);
|
||||
if (map==MI_BITMAP_FIELD_FULL) return false; // short cut
|
||||
|
||||
// search for 0-bit sequence of length count
|
||||
const uintptr_t mask = mi_bitmap_mask_(count, 0);
|
||||
const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count;
|
||||
|
||||
#ifdef MI_HAVE_BITSCAN
|
||||
size_t bitidx = mi_bsf(~map); // quickly find the first zero bit if possible
|
||||
#else
|
||||
size_t bitidx = 0; // otherwise start at 0
|
||||
#endif
|
||||
uintptr_t m = (mask << bitidx); // invariant: m == mask shifted by bitidx
|
||||
|
||||
// scan linearly for a free range of zero bits
|
||||
while (bitidx <= bitidx_max) {
|
||||
if ((map & m) == 0) { // are the mask bits free at bitidx?
|
||||
mi_assert_internal((m >> bitidx) == mask); // no overflow?
|
||||
const uintptr_t newmap = map | m;
|
||||
mi_assert_internal((newmap^map) >> bitidx == mask);
|
||||
if (!mi_atomic_cas_weak(field, newmap, map)) { // TODO: use strong cas here?
|
||||
// no success, another thread claimed concurrently.. keep going
|
||||
map = mi_atomic_read(field);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// success, we claimed the bits!
|
||||
*bitmap_idx = mi_bitmap_index_create(idx, bitidx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// on to the next bit range
|
||||
#ifdef MI_HAVE_BITSCAN
|
||||
const size_t shift = (count == 1 ? 1 : mi_bsr(map & m) - bitidx + 1);
|
||||
mi_assert_internal(shift > 0 && shift <= count);
|
||||
#else
|
||||
const size_t shift = 1;
|
||||
#endif
|
||||
bitidx += shift;
|
||||
m <<= shift;
|
||||
}
|
||||
}
|
||||
// no bits found
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Find `count` bits of 0 and set them to 1 atomically; returns `true` on success.
|
||||
// For now, `count` can be at most MI_BITMAP_FIELD_BITS and will never span fields.
|
||||
static inline bool mi_bitmap_try_find_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t* bitmap_idx) {
|
||||
for (size_t idx = 0; idx < bitmap_fields; idx++) {
|
||||
if (mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||
// Returns `true` if all `count` bits were 1 previously.
|
||||
static inline bool mi_bitmap_unclaim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||
mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields);
|
||||
// mi_assert_internal((bitmap[idx] & mask) == mask);
|
||||
uintptr_t prev = mi_atomic_and(&bitmap[idx], ~mask);
|
||||
return ((prev & mask) == mask);
|
||||
}
|
||||
|
||||
|
||||
// Set `count` bits at `bitmap_idx` to 1 atomically
|
||||
// Returns `true` if all `count` bits were 0 previously. `any_zero` is `true` if there was at least one zero bit.
|
||||
static inline bool mi_bitmap_claim(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_zero) {
|
||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||
mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields);
|
||||
//mi_assert_internal(any_zero != NULL || (bitmap[idx] & mask) == 0);
|
||||
uintptr_t prev = mi_atomic_or(&bitmap[idx], mask);
|
||||
if (any_zero != NULL) *any_zero = ((prev & mask) != mask);
|
||||
return ((prev & mask) == 0);
|
||||
}
|
||||
|
||||
// Returns `true` if all `count` bits were 1. `any_ones` is `true` if there was at least one bit set to one.
|
||||
static inline bool mi_bitmap_is_claimedx(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx, bool* any_ones) {
|
||||
const size_t idx = mi_bitmap_index_field(bitmap_idx);
|
||||
const size_t bitidx = mi_bitmap_index_bit_in_field(bitmap_idx);
|
||||
const uintptr_t mask = mi_bitmap_mask_(count, bitidx);
|
||||
mi_assert_internal(bitmap_fields > idx); UNUSED(bitmap_fields);
|
||||
uintptr_t field = mi_atomic_read_relaxed(&bitmap[idx]);
|
||||
if (any_ones != NULL) *any_ones = ((field & mask) != 0);
|
||||
return ((field & mask) == mask);
|
||||
}
|
||||
|
||||
static inline bool mi_bitmap_is_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||
return mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, NULL);
|
||||
}
|
||||
|
||||
static inline bool mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t count, mi_bitmap_index_t bitmap_idx) {
|
||||
bool any_ones;
|
||||
mi_bitmap_is_claimedx(bitmap, bitmap_fields, count, bitmap_idx, &any_ones);
|
||||
return any_ones;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
172
src/heap.c
172
src/heap.c
@ -34,7 +34,7 @@ static bool mi_heap_visit_pages(mi_heap_t* heap, heap_page_visitor_fun* fn, void
|
||||
mi_page_t* page = pq->first;
|
||||
while(page != NULL) {
|
||||
mi_page_t* next = page->next; // save next in case the page gets removed from the queue
|
||||
mi_assert_internal(page->heap == heap);
|
||||
mi_assert_internal(mi_page_heap(page) == heap);
|
||||
count++;
|
||||
if (!fn(heap, pq, page, arg1, arg2)) return false;
|
||||
page = next; // and continue
|
||||
@ -45,21 +45,22 @@ static bool mi_heap_visit_pages(mi_heap_t* heap, heap_page_visitor_fun* fn, void
|
||||
}
|
||||
|
||||
|
||||
#if MI_DEBUG>1
|
||||
static bool _mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) {
|
||||
#if MI_DEBUG>=2
|
||||
static bool mi_heap_page_is_valid(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg1, void* arg2) {
|
||||
UNUSED(arg1);
|
||||
UNUSED(arg2);
|
||||
UNUSED(pq);
|
||||
mi_assert_internal(page->heap == heap);
|
||||
mi_assert_internal(mi_page_heap(page) == heap);
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
mi_assert_internal(segment->thread_id == heap->thread_id);
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if MI_DEBUG>=3
|
||||
static bool mi_heap_is_valid(mi_heap_t* heap) {
|
||||
mi_assert_internal(heap!=NULL);
|
||||
mi_heap_visit_pages(heap, &_mi_heap_page_is_valid, NULL, NULL);
|
||||
mi_heap_visit_pages(heap, &mi_heap_page_is_valid, NULL, NULL);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -75,22 +76,24 @@ static bool mi_heap_is_valid(mi_heap_t* heap) {
|
||||
----------------------------------------------------------- */
|
||||
|
||||
typedef enum mi_collect_e {
|
||||
NORMAL,
|
||||
FORCE,
|
||||
ABANDON
|
||||
MI_NORMAL,
|
||||
MI_FORCE,
|
||||
MI_ABANDON
|
||||
} mi_collect_t;
|
||||
|
||||
|
||||
static bool mi_heap_page_collect(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_t* page, void* arg_collect, void* arg2 ) {
|
||||
UNUSED(arg2);
|
||||
UNUSED(heap);
|
||||
mi_assert_internal(mi_heap_page_is_valid(heap, pq, page, NULL, NULL));
|
||||
mi_collect_t collect = *((mi_collect_t*)arg_collect);
|
||||
_mi_page_free_collect(page, collect >= ABANDON);
|
||||
_mi_page_free_collect(page, collect >= MI_FORCE);
|
||||
if (mi_page_all_free(page)) {
|
||||
// no more used blocks, free the page. TODO: should we retire here and be less aggressive?
|
||||
_mi_page_free(page, pq, collect != NORMAL);
|
||||
// no more used blocks, free the page.
|
||||
// note: this will free retired pages as well.
|
||||
_mi_page_free(page, pq, collect >= MI_FORCE);
|
||||
}
|
||||
else if (collect == ABANDON) {
|
||||
else if (collect == MI_ABANDON) {
|
||||
// still used blocks but the thread is done; abandon the page
|
||||
_mi_page_abandon(page, pq);
|
||||
}
|
||||
@ -102,63 +105,62 @@ static bool mi_heap_page_never_delayed_free(mi_heap_t* heap, mi_page_queue_t* pq
|
||||
UNUSED(arg2);
|
||||
UNUSED(heap);
|
||||
UNUSED(pq);
|
||||
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE);
|
||||
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false);
|
||||
return true; // don't break
|
||||
}
|
||||
|
||||
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) {
|
||||
// this may free some segments (but also take ownership of abandoned pages)
|
||||
_mi_segment_try_reclaim_abandoned(heap, false, &heap->tld->segments);
|
||||
}
|
||||
#if MI_DEBUG
|
||||
else if (collect == ABANDON && _mi_is_main_thread() && mi_heap_is_backing(heap)) {
|
||||
// the main thread is abandoned, try to free all abandoned segments.
|
||||
// if all memory is freed by now, all segments should be freed.
|
||||
_mi_segment_try_reclaim_abandoned(heap, true, &heap->tld->segments);
|
||||
}
|
||||
#endif
|
||||
_mi_deferred_free(heap, collect >= MI_FORCE);
|
||||
|
||||
// note: never reclaim on collect but leave it to threads that need storage to reclaim
|
||||
if (
|
||||
#ifdef NDEBUG
|
||||
collect == MI_FORCE
|
||||
#else
|
||||
collect >= MI_FORCE
|
||||
#endif
|
||||
&& _mi_is_main_thread() && mi_heap_is_backing(heap) && !heap->no_reclaim)
|
||||
{
|
||||
// the main thread is abandoned (end-of-program), try to reclaim all abandoned segments.
|
||||
// if all memory is freed by now, all segments should be freed.
|
||||
_mi_abandoned_reclaim_all(heap, &heap->tld->segments);
|
||||
}
|
||||
|
||||
|
||||
// if abandoning, mark all pages to no longer add to delayed_free
|
||||
if (collect == ABANDON) {
|
||||
//for (mi_page_t* page = heap->pages[MI_BIN_FULL].first; page != NULL; page = page->next) {
|
||||
// _mi_page_use_delayed_free(page, false); // set thread_free.delayed to MI_NO_DELAYED_FREE
|
||||
//}
|
||||
if (collect == MI_ABANDON) {
|
||||
mi_heap_visit_pages(heap, &mi_heap_page_never_delayed_free, NULL, NULL);
|
||||
}
|
||||
|
||||
// free thread delayed blocks.
|
||||
// (if abandoning, after this there are no more local references into the pages.)
|
||||
// free thread delayed blocks.
|
||||
// (if abandoning, after this there are no more thread-delayed references into the pages.)
|
||||
_mi_heap_delayed_free(heap);
|
||||
|
||||
// collect all pages owned by this thread
|
||||
mi_heap_visit_pages(heap, &mi_heap_page_collect, &collect, NULL);
|
||||
mi_assert_internal( collect != ABANDON || heap->thread_delayed_free == NULL );
|
||||
|
||||
mi_assert_internal( collect != MI_ABANDON || mi_atomic_read_ptr(mi_block_t,&heap->thread_delayed_free) == NULL );
|
||||
|
||||
// collect segment caches
|
||||
if (collect >= FORCE) {
|
||||
if (collect >= MI_FORCE) {
|
||||
_mi_segment_thread_collect(&heap->tld->segments);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// collect regions
|
||||
if (collect >= FORCE && _mi_is_main_thread()) {
|
||||
_mi_mem_collect(&heap->tld->stats);
|
||||
if (collect >= MI_FORCE && _mi_is_main_thread() && mi_heap_is_backing(heap)) {
|
||||
_mi_mem_collect(&heap->tld->os);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void _mi_heap_collect_abandon(mi_heap_t* heap) {
|
||||
mi_heap_collect_ex(heap, ABANDON);
|
||||
mi_heap_collect_ex(heap, MI_ABANDON);
|
||||
}
|
||||
|
||||
void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept {
|
||||
mi_heap_collect_ex(heap, (force ? FORCE : NORMAL));
|
||||
mi_heap_collect_ex(heap, (force ? MI_FORCE : MI_NORMAL));
|
||||
}
|
||||
|
||||
void mi_collect(bool force) mi_attr_noexcept {
|
||||
@ -171,7 +173,7 @@ void mi_collect(bool force) mi_attr_noexcept {
|
||||
----------------------------------------------------------- */
|
||||
|
||||
mi_heap_t* mi_heap_get_default(void) {
|
||||
mi_thread_init();
|
||||
mi_thread_init();
|
||||
return mi_get_default_heap();
|
||||
}
|
||||
|
||||
@ -184,12 +186,6 @@ mi_heap_t* mi_heap_get_backing(void) {
|
||||
return bheap;
|
||||
}
|
||||
|
||||
uintptr_t _mi_heap_random(mi_heap_t* heap) {
|
||||
uintptr_t r = heap->random;
|
||||
heap->random = _mi_random_shuffle(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
mi_heap_t* mi_heap_new(void) {
|
||||
mi_heap_t* bheap = mi_heap_get_backing();
|
||||
mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t);
|
||||
@ -197,12 +193,18 @@ mi_heap_t* mi_heap_new(void) {
|
||||
memcpy(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
||||
heap->tld = bheap->tld;
|
||||
heap->thread_id = _mi_thread_id();
|
||||
heap->cookie = ((uintptr_t)heap ^ _mi_heap_random(bheap)) | 1;
|
||||
heap->random = _mi_heap_random(bheap);
|
||||
_mi_random_split(&bheap->random, &heap->random);
|
||||
heap->cookie = _mi_heap_random_next(heap) | 1;
|
||||
heap->key[0] = _mi_heap_random_next(heap);
|
||||
heap->key[1] = _mi_heap_random_next(heap);
|
||||
heap->no_reclaim = true; // don't reclaim abandoned pages or otherwise destroy is unsafe
|
||||
return heap;
|
||||
}
|
||||
|
||||
uintptr_t _mi_heap_random_next(mi_heap_t* heap) {
|
||||
return _mi_random_next(&heap->random);
|
||||
}
|
||||
|
||||
// zero out the page queues
|
||||
static void mi_heap_reset_pages(mi_heap_t* heap) {
|
||||
mi_assert_internal(mi_heap_is_initialized(heap));
|
||||
@ -220,7 +222,7 @@ static void mi_heap_reset_pages(mi_heap_t* heap) {
|
||||
static void mi_heap_free(mi_heap_t* heap) {
|
||||
mi_assert_internal(mi_heap_is_initialized(heap));
|
||||
if (mi_heap_is_backing(heap)) return; // dont free the backing heap
|
||||
|
||||
|
||||
// reset default
|
||||
if (mi_heap_is_default(heap)) {
|
||||
_mi_heap_set_default_direct(heap->tld->heap_backing);
|
||||
@ -241,30 +243,35 @@ static bool _mi_heap_page_destroy(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_
|
||||
UNUSED(pq);
|
||||
|
||||
// ensure no more thread_delayed_free will be added
|
||||
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE);
|
||||
_mi_page_use_delayed_free(page, MI_NEVER_DELAYED_FREE, false);
|
||||
|
||||
// stats
|
||||
if (page->block_size > MI_LARGE_OBJ_SIZE_MAX) {
|
||||
if (page->block_size > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_decrease(&heap->tld->stats.giant,page->block_size);
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
if (bsize > MI_LARGE_OBJ_SIZE_MAX) {
|
||||
if (bsize > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_decrease(&heap->tld->stats.giant, bsize);
|
||||
}
|
||||
else {
|
||||
_mi_stat_decrease(&heap->tld->stats.huge, page->block_size);
|
||||
_mi_stat_decrease(&heap->tld->stats.huge, bsize);
|
||||
}
|
||||
}
|
||||
#if (MI_STAT>1)
|
||||
size_t inuse = page->used - page->thread_freed;
|
||||
if (page->block_size <= MI_LARGE_OBJ_SIZE_MAX) {
|
||||
mi_heap_stat_decrease(heap,normal[_mi_bin(page->block_size)], inuse);
|
||||
#if (MI_STAT>1)
|
||||
_mi_page_free_collect(page, false); // update used count
|
||||
const size_t inuse = page->used;
|
||||
if (bsize <= MI_LARGE_OBJ_SIZE_MAX) {
|
||||
mi_heap_stat_decrease(heap, normal[_mi_bin(bsize)], inuse);
|
||||
}
|
||||
mi_heap_stat_decrease(heap,malloc, page->block_size * inuse); // todo: off for aligned blocks...
|
||||
#endif
|
||||
mi_heap_stat_decrease(heap, malloc, bsize * inuse); // todo: off for aligned blocks...
|
||||
#endif
|
||||
|
||||
// pretend it is all free now
|
||||
mi_assert_internal(page->thread_freed<=0xFFFF);
|
||||
page->used = (uint16_t)page->thread_freed;
|
||||
/// pretend it is all free now
|
||||
mi_assert_internal(mi_page_thread_free(page) == NULL);
|
||||
page->used = 0;
|
||||
|
||||
// and free the page
|
||||
// mi_page_free(page,false);
|
||||
page->next = NULL;
|
||||
page->prev = NULL;
|
||||
_mi_segment_page_free(page,false /* no force? */, &heap->tld->segments);
|
||||
|
||||
return true; // keep going
|
||||
@ -303,7 +310,7 @@ static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) {
|
||||
if (from==NULL || from->page_count == 0) return;
|
||||
|
||||
// unfull all full pages in the `from` heap
|
||||
mi_page_t* page = from->pages[MI_BIN_FULL].first;
|
||||
mi_page_t* page = from->pages[MI_BIN_FULL].first;
|
||||
while (page != NULL) {
|
||||
mi_page_t* next = page->next;
|
||||
_mi_page_unfull(page);
|
||||
@ -315,7 +322,7 @@ static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) {
|
||||
_mi_heap_delayed_free(from);
|
||||
|
||||
// transfer all pages by appending the queues; this will set
|
||||
// a new heap field which is ok as all pages are unfull'd and thus
|
||||
// a new heap field which is ok as all pages are unfull'd and thus
|
||||
// other threads won't access this field anymore (see `mi_free_block_mt`)
|
||||
for (size_t i = 0; i < MI_BIN_FULL; i++) {
|
||||
mi_page_queue_t* pq = &heap->pages[i];
|
||||
@ -326,7 +333,7 @@ static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) {
|
||||
}
|
||||
mi_assert_internal(from->thread_delayed_free == NULL);
|
||||
mi_assert_internal(from->page_count == 0);
|
||||
|
||||
|
||||
// and reset the `from` heap
|
||||
mi_heap_reset_pages(from);
|
||||
}
|
||||
@ -354,7 +361,7 @@ mi_heap_t* mi_heap_set_default(mi_heap_t* heap) {
|
||||
mi_assert(mi_heap_is_initialized(heap));
|
||||
if (!mi_heap_is_initialized(heap)) return NULL;
|
||||
mi_assert_expensive(mi_heap_is_valid(heap));
|
||||
mi_heap_t* old = mi_get_default_heap();
|
||||
mi_heap_t* old = mi_get_default_heap();
|
||||
_mi_heap_set_default_direct(heap);
|
||||
return old;
|
||||
}
|
||||
@ -373,7 +380,7 @@ static mi_heap_t* mi_heap_of_block(const void* p) {
|
||||
bool valid = (_mi_ptr_cookie(segment) == segment->cookie);
|
||||
mi_assert_internal(valid);
|
||||
if (mi_unlikely(!valid)) return NULL;
|
||||
return _mi_segment_page_of(segment,p)->heap;
|
||||
return mi_page_heap(_mi_segment_page_of(segment,p));
|
||||
}
|
||||
|
||||
bool mi_heap_contains_block(mi_heap_t* heap, const void* p) {
|
||||
@ -389,7 +396,7 @@ static bool mi_heap_page_check_owned(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa
|
||||
bool* found = (bool*)vfound;
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
void* start = _mi_page_start(segment, page, NULL);
|
||||
void* end = (uint8_t*)start + (page->capacity * page->block_size);
|
||||
void* end = (uint8_t*)start + (page->capacity * mi_page_block_size(page));
|
||||
*found = (p >= start && p < end);
|
||||
return (!*found); // continue if not found
|
||||
}
|
||||
@ -431,13 +438,14 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
|
||||
mi_assert_internal(page->local_free == NULL);
|
||||
if (page->used == 0) return true;
|
||||
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
size_t psize;
|
||||
uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize);
|
||||
|
||||
if (page->capacity == 1) {
|
||||
// optimize page with one block
|
||||
mi_assert_internal(page->used == 1 && page->free == NULL);
|
||||
return visitor(page->heap, area, pstart, page->block_size, arg);
|
||||
return visitor(mi_page_heap(page), area, pstart, bsize, arg);
|
||||
}
|
||||
|
||||
// create a bitmap of free blocks.
|
||||
@ -450,8 +458,8 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
|
||||
free_count++;
|
||||
mi_assert_internal((uint8_t*)block >= pstart && (uint8_t*)block < (pstart + psize));
|
||||
size_t offset = (uint8_t*)block - pstart;
|
||||
mi_assert_internal(offset % page->block_size == 0);
|
||||
size_t blockidx = offset / page->block_size; // Todo: avoid division?
|
||||
mi_assert_internal(offset % bsize == 0);
|
||||
size_t blockidx = offset / bsize; // Todo: avoid division?
|
||||
mi_assert_internal( blockidx < MI_MAX_BLOCKS);
|
||||
size_t bitidx = (blockidx / sizeof(uintptr_t));
|
||||
size_t bit = blockidx - (bitidx * sizeof(uintptr_t));
|
||||
@ -470,8 +478,8 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
|
||||
}
|
||||
else if ((m & ((uintptr_t)1 << bit)) == 0) {
|
||||
used_count++;
|
||||
uint8_t* block = pstart + (i * page->block_size);
|
||||
if (!visitor(page->heap, area, block, page->block_size, arg)) return false;
|
||||
uint8_t* block = pstart + (i * bsize);
|
||||
if (!visitor(mi_page_heap(page), area, block, bsize, arg)) return false;
|
||||
}
|
||||
}
|
||||
mi_assert_internal(page->used == used_count);
|
||||
@ -486,12 +494,13 @@ static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa
|
||||
UNUSED(pq);
|
||||
mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun;
|
||||
mi_heap_area_ex_t xarea;
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
xarea.page = page;
|
||||
xarea.area.reserved = page->reserved * page->block_size;
|
||||
xarea.area.committed = page->capacity * page->block_size;
|
||||
xarea.area.reserved = page->reserved * bsize;
|
||||
xarea.area.committed = page->capacity * bsize;
|
||||
xarea.area.blocks = _mi_page_start(_mi_page_segment(page), page, NULL);
|
||||
xarea.area.used = page->used - page->thread_freed; // race is ok
|
||||
xarea.area.block_size = page->block_size;
|
||||
xarea.area.used = page->used;
|
||||
xarea.area.block_size = bsize;
|
||||
return fun(heap, &xarea, arg);
|
||||
}
|
||||
|
||||
@ -524,4 +533,3 @@ bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_vis
|
||||
mi_visit_blocks_args_t args = { visit_blocks, visitor, arg };
|
||||
return mi_heap_visit_areas(heap, &mi_heap_area_visitor, &args);
|
||||
}
|
||||
|
||||
|
176
src/init.c
176
src/init.c
@ -12,19 +12,22 @@ 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, false, false, false,
|
||||
0, // capacity
|
||||
0, // reserved capacity
|
||||
{ 0 }, // flags
|
||||
false, // is_zero
|
||||
0, // retire_expire
|
||||
NULL, // free
|
||||
#if MI_ENCODE_FREELIST
|
||||
0,
|
||||
{ 0, 0 },
|
||||
#endif
|
||||
0, // used
|
||||
NULL,
|
||||
ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0),
|
||||
0, NULL, NULL, NULL
|
||||
#if (MI_INTPTR_SIZE==8 && defined(MI_ENCODE_FREELIST)) || (MI_INTPTR_SIZE==4 && !defined(MI_ENCODE_FREELIST))
|
||||
, { NULL } // padding
|
||||
#endif
|
||||
0, // xblock_size
|
||||
NULL, // local_free
|
||||
ATOMIC_VAR_INIT(0), // xthread_free
|
||||
ATOMIC_VAR_INIT(0), // xheap
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
#define MI_PAGE_EMPTY() ((mi_page_t*)&_mi_page_empty)
|
||||
@ -83,10 +86,11 @@ const mi_heap_t _mi_heap_empty = {
|
||||
MI_SMALL_PAGES_EMPTY,
|
||||
MI_PAGE_QUEUES_EMPTY,
|
||||
ATOMIC_VAR_INIT(NULL),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // tid
|
||||
0, // cookie
|
||||
{ 0, 0 }, // keys
|
||||
{ {0}, {0}, 0 },
|
||||
0, // page count
|
||||
false
|
||||
};
|
||||
|
||||
@ -95,100 +99,48 @@ 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)))
|
||||
#define tld_main_os ((mi_os_tld_t*)((uint8_t*)&tld_main + offsetof(mi_tld_t,os)))
|
||||
|
||||
static mi_tld_t tld_main = {
|
||||
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
|
||||
{ MI_STATS_NULL } // stats
|
||||
{ { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0},
|
||||
0, 0, 0, 0, 0, 0, NULL,
|
||||
tld_main_stats, tld_main_os
|
||||
}, // segments
|
||||
{ 0, tld_main_stats }, // os
|
||||
{ MI_STATS_NULL } // stats
|
||||
};
|
||||
|
||||
#if MI_INTPTR_SIZE==8
|
||||
#define MI_INIT_COOKIE (0xCDCDCDCDCDCDCDCDUL)
|
||||
#else
|
||||
#define MI_INIT_COOKIE (0xCDCDCDCDUL)
|
||||
#endif
|
||||
|
||||
mi_heap_t _mi_heap_main = {
|
||||
&tld_main,
|
||||
MI_SMALL_PAGES_EMPTY,
|
||||
MI_PAGE_QUEUES_EMPTY,
|
||||
NULL,
|
||||
0, // thread id
|
||||
#if MI_INTPTR_SIZE==8 // the cookie of the main heap can be fixed (unlike page cookies that need to be secure!)
|
||||
0xCDCDCDCDCDCDCDCDUL,
|
||||
#else
|
||||
0xCDCDCDCDUL,
|
||||
#endif
|
||||
0, // random
|
||||
0, // page count
|
||||
false // can reclaim
|
||||
ATOMIC_VAR_INIT(NULL),
|
||||
0, // thread id
|
||||
MI_INIT_COOKIE, // initial cookie
|
||||
{ MI_INIT_COOKIE, MI_INIT_COOKIE }, // the key of the main heap can be fixed (unlike page keys that need to be secure!)
|
||||
{ {0}, {0}, 0 }, // random
|
||||
0, // page count
|
||||
false // can reclaim
|
||||
};
|
||||
|
||||
bool _mi_process_is_initialized = false; // set to `true` in `mi_process_init`.
|
||||
|
||||
mi_stats_t _mi_stats_main = { MI_STATS_NULL };
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Initialization of random numbers
|
||||
----------------------------------------------------------- */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
uintptr_t _mi_random_shuffle(uintptr_t x) {
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
// by Sebastiano Vigna, see: <http://xoshiro.di.unimi.it/splitmix64.c>
|
||||
x ^= x >> 30;
|
||||
x *= 0xbf58476d1ce4e5b9UL;
|
||||
x ^= x >> 27;
|
||||
x *= 0x94d049bb133111ebUL;
|
||||
x ^= x >> 31;
|
||||
#elif (MI_INTPTR_SIZE==4)
|
||||
// by Chris Wellons, see: <https://nullprogram.com/blog/2018/07/31/>
|
||||
x ^= x >> 16;
|
||||
x *= 0x7feb352dUL;
|
||||
x ^= x >> 15;
|
||||
x *= 0x846ca68bUL;
|
||||
x ^= x >> 16;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
uintptr_t _mi_random_init(uintptr_t seed /* can be zero */) {
|
||||
#ifdef __wasi__ // no ASLR when using WebAssembly, and time granularity may be coarse
|
||||
uintptr_t x;
|
||||
arc4random_buf(&x, sizeof x);
|
||||
#else
|
||||
// Hopefully, ASLR makes our function address random
|
||||
uintptr_t x = (uintptr_t)((void*)&_mi_random_init);
|
||||
x ^= seed;
|
||||
// xor with high res time
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER pcount;
|
||||
QueryPerformanceCounter(&pcount);
|
||||
x ^= (uintptr_t)(pcount.QuadPart);
|
||||
#elif defined(__APPLE__)
|
||||
x ^= (uintptr_t)mach_absolute_time();
|
||||
#else
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
x ^= (uintptr_t)time.tv_sec;
|
||||
x ^= (uintptr_t)time.tv_nsec;
|
||||
#endif
|
||||
// and do a few randomization steps
|
||||
uintptr_t max = ((x ^ (x >> 17)) & 0x0F) + 1;
|
||||
for (uintptr_t i = 0; i < max; i++) {
|
||||
x = _mi_random_shuffle(x);
|
||||
}
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Initialization and freeing of the thread local heaps
|
||||
----------------------------------------------------------- */
|
||||
|
||||
// note: in x64 in release build `sizeof(mi_thread_data_t)` is under 4KiB (= OS page size).
|
||||
typedef struct mi_thread_data_s {
|
||||
mi_heap_t heap; // must come first due to cast in `_mi_heap_done`
|
||||
mi_tld_t tld;
|
||||
@ -203,22 +155,25 @@ static bool _mi_heap_init(void) {
|
||||
mi_assert_internal(_mi_heap_default->tld->heap_backing == mi_get_default_heap());
|
||||
}
|
||||
else {
|
||||
// use `_mi_os_alloc` to allocate directly from the OS
|
||||
// use `_mi_os_alloc` to allocate directly from the OS
|
||||
mi_thread_data_t* td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t),&_mi_stats_main); // Todo: more efficient allocation?
|
||||
if (td == NULL) {
|
||||
_mi_error_message("failed to allocate thread local heap memory\n");
|
||||
_mi_error_message(ENOMEM, "failed to allocate thread local heap memory\n");
|
||||
return false;
|
||||
}
|
||||
// OS allocated so already zero initialized
|
||||
mi_tld_t* tld = &td->tld;
|
||||
mi_heap_t* heap = &td->heap;
|
||||
memcpy(heap, &_mi_heap_empty, sizeof(*heap));
|
||||
heap->thread_id = _mi_thread_id();
|
||||
heap->random = _mi_random_init(heap->thread_id);
|
||||
heap->cookie = ((uintptr_t)heap ^ _mi_heap_random(heap)) | 1;
|
||||
heap->tld = tld;
|
||||
memset(tld, 0, sizeof(*tld));
|
||||
_mi_random_init(&heap->random);
|
||||
heap->cookie = _mi_heap_random_next(heap) | 1;
|
||||
heap->key[0] = _mi_heap_random_next(heap);
|
||||
heap->key[1] = _mi_heap_random_next(heap);
|
||||
heap->tld = tld;
|
||||
tld->heap_backing = heap;
|
||||
tld->segments.stats = &tld->stats;
|
||||
tld->segments.os = &tld->os;
|
||||
tld->os.stats = &tld->stats;
|
||||
_mi_heap_set_default_direct(heap);
|
||||
}
|
||||
@ -237,7 +192,7 @@ static bool _mi_heap_done(mi_heap_t* heap) {
|
||||
// switch to backing heap and free it
|
||||
heap = heap->tld->heap_backing;
|
||||
if (!mi_heap_is_initialized(heap)) return false;
|
||||
|
||||
|
||||
// collect if not the main thread
|
||||
if (heap != &_mi_heap_main) {
|
||||
_mi_heap_collect_abandon(heap);
|
||||
@ -248,6 +203,7 @@ static bool _mi_heap_done(mi_heap_t* heap) {
|
||||
|
||||
// free if not the main thread
|
||||
if (heap != &_mi_heap_main) {
|
||||
mi_assert_internal(heap->tld->segments.count == 0);
|
||||
_mi_os_free(heap, sizeof(mi_thread_data_t), &_mi_stats_main);
|
||||
}
|
||||
#if (MI_DEBUG > 0)
|
||||
@ -334,7 +290,7 @@ void mi_thread_init(void) mi_attr_noexcept
|
||||
mi_process_init();
|
||||
|
||||
// initialize the thread local default heap
|
||||
// (this will call `_mi_heap_set_default_direct` and thus set the
|
||||
// (this will call `_mi_heap_set_default_direct` and thus set the
|
||||
// fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called)
|
||||
if (_mi_heap_init()) return; // returns true if already initialized
|
||||
|
||||
@ -368,9 +324,9 @@ void _mi_heap_set_default_direct(mi_heap_t* heap) {
|
||||
#if defined(_WIN32) && defined(MI_SHARED_LIB)
|
||||
// nothing to do as it is done in DllMain
|
||||
#elif defined(_WIN32) && !defined(MI_SHARED_LIB)
|
||||
FlsSetValue(mi_fls_key, heap);
|
||||
FlsSetValue(mi_fls_key, heap);
|
||||
#elif defined(MI_USE_PTHREADS)
|
||||
pthread_setspecific(mi_pthread_key, heap);
|
||||
pthread_setspecific(mi_pthread_key, heap);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -394,7 +350,7 @@ bool mi_is_redirected() mi_attr_noexcept {
|
||||
}
|
||||
|
||||
// Communicate with the redirection module on Windows
|
||||
#if defined(_WIN32) && defined(MI_SHARED_LIB)
|
||||
#if defined(_WIN32) && defined(MI_SHARED_LIB)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -438,13 +394,7 @@ static void mi_process_load(void) {
|
||||
const char* msg = NULL;
|
||||
mi_allocator_init(&msg);
|
||||
if (msg != NULL && (mi_option_is_enabled(mi_option_verbose) || mi_option_is_enabled(mi_option_show_errors))) {
|
||||
_mi_fputs(NULL,NULL,msg);
|
||||
}
|
||||
|
||||
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, NULL);
|
||||
_mi_fputs(NULL,NULL,NULL,msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,16 +405,17 @@ void mi_process_init(void) mi_attr_noexcept {
|
||||
// access _mi_heap_default before setting _mi_process_is_initialized to ensure
|
||||
// that the TLS slot is allocated without getting into recursion on macOS
|
||||
// when using dynamic linking with interpose.
|
||||
mi_heap_t* h = mi_get_default_heap();
|
||||
mi_get_default_heap();
|
||||
_mi_process_is_initialized = true;
|
||||
|
||||
_mi_heap_main.thread_id = _mi_thread_id();
|
||||
_mi_verbose_message("process init: 0x%zx\n", _mi_heap_main.thread_id);
|
||||
uintptr_t random = _mi_random_init(_mi_heap_main.thread_id) ^ (uintptr_t)h;
|
||||
#ifndef __APPLE__
|
||||
_mi_heap_main.cookie = (uintptr_t)&_mi_heap_main ^ random;
|
||||
_mi_random_init(&_mi_heap_main.random);
|
||||
#ifndef __APPLE__ // TODO: fix this? cannot update cookie if allocation already happened..
|
||||
_mi_heap_main.cookie = _mi_heap_random_next(&_mi_heap_main);
|
||||
_mi_heap_main.key[0] = _mi_heap_random_next(&_mi_heap_main);
|
||||
_mi_heap_main.key[1] = _mi_heap_random_next(&_mi_heap_main);
|
||||
#endif
|
||||
_mi_heap_main.random = _mi_random_shuffle(random);
|
||||
mi_process_setup_auto_thread_done();
|
||||
_mi_os_init();
|
||||
#if (MI_DEBUG)
|
||||
@ -473,6 +424,11 @@ void mi_process_init(void) mi_attr_noexcept {
|
||||
_mi_verbose_message("secure level: %d\n", MI_SECURE);
|
||||
mi_thread_init();
|
||||
mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL)
|
||||
|
||||
if (mi_option_is_enabled(mi_option_reserve_huge_os_pages)) {
|
||||
size_t pages = mi_option_get(mi_option_reserve_huge_os_pages);
|
||||
mi_reserve_huge_os_pages_interleave(pages, 0, pages*500);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the process is done (through `at_exit`)
|
||||
@ -499,7 +455,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
|
||||
// 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);
|
||||
|
546
src/memory.c
546
src/memory.c
@ -1,546 +0,0 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 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.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
This implements a layer between the raw OS memory (VirtualAlloc/mmap/sbrk/..)
|
||||
and the segment and huge object allocation by mimalloc. There may be multiple
|
||||
implementations of this (one could be the identity going directly to the OS,
|
||||
another could be a simple cache etc), but the current one uses large "regions".
|
||||
In contrast to the rest of mimalloc, the "regions" are shared between threads and
|
||||
need to be accessed using atomic operations.
|
||||
We need this memory layer between the raw OS calls because of:
|
||||
1. on `sbrk` like systems (like WebAssembly) we need our own memory maps in order
|
||||
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 :-( (`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.
|
||||
|
||||
Possible issues:
|
||||
- (2) can potentially be addressed too with a small cache per thread which is much
|
||||
simpler. Generally though that requires shrinking of huge pages, and may overuse
|
||||
memory per thread. (and is not compatible with `sbrk`).
|
||||
- Since the current regions are per-process, we need atomic operations to
|
||||
claim blocks which may be contended
|
||||
- In the worst case, we need to search the whole region map (16KiB for 256GiB)
|
||||
linearly. At what point will direct OS calls be faster? Is there a way to
|
||||
do this better without adding too much complexity?
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc-internal.h"
|
||||
#include "mimalloc-atomic.h"
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
// 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, 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, 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);
|
||||
bool _mi_os_is_huge_reserved(void* p);
|
||||
|
||||
// Constants
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
#define MI_HEAP_REGION_MAX_SIZE (256 * (1ULL << 30)) // 256GiB => 16KiB for the region map
|
||||
#elif (MI_INTPTR_SIZE==4)
|
||||
#define MI_HEAP_REGION_MAX_SIZE (3 * (1UL << 30)) // 3GiB => 196 bytes for the region map
|
||||
#else
|
||||
#error "define the maximum heap space allowed for regions on this platform"
|
||||
#endif
|
||||
|
||||
#define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE
|
||||
|
||||
#define MI_REGION_MAP_BITS (MI_INTPTR_SIZE * 8)
|
||||
#define MI_REGION_SIZE (MI_SEGMENT_SIZE * MI_REGION_MAP_BITS)
|
||||
#define MI_REGION_MAX_ALLOC_SIZE ((MI_REGION_MAP_BITS/4)*MI_SEGMENT_SIZE) // 64MiB
|
||||
#define MI_REGION_MAX (MI_HEAP_REGION_MAX_SIZE / MI_REGION_SIZE)
|
||||
#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 | ((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) {
|
||||
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(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;
|
||||
|
||||
|
||||
// The region map; 16KiB for a 256GiB HEAP_REGION_MAX
|
||||
// TODO: in the future, maintain a map per NUMA node for numa aware allocation
|
||||
static mem_region_t regions[MI_REGION_MAX];
|
||||
|
||||
static volatile _Atomic(uintptr_t) regions_count; // = 0; // allocated regions
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Utility functions
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// Blocks (of 4MiB) needed for the given size.
|
||||
static size_t mi_region_block_count(size_t size) {
|
||||
mi_assert_internal(size <= MI_REGION_MAX_ALLOC_SIZE);
|
||||
return (size + MI_SEGMENT_SIZE - 1) / MI_SEGMENT_SIZE;
|
||||
}
|
||||
|
||||
// The bit mask for a given number of blocks at a specified bit index.
|
||||
static uintptr_t mi_region_block_mask(size_t blocks, size_t bitidx) {
|
||||
mi_assert_internal(blocks + bitidx <= MI_REGION_MAP_BITS);
|
||||
return ((((uintptr_t)1 << blocks) - 1) << bitidx);
|
||||
}
|
||||
|
||||
// Return a rounded commit/reset size such that we don't fragment large OS pages into small ones.
|
||||
static size_t mi_good_commit_size(size_t size) {
|
||||
if (size > (SIZE_MAX - _mi_os_large_page_size())) return size;
|
||||
return _mi_align_up(size, _mi_os_large_page_size());
|
||||
}
|
||||
|
||||
// Return if a pointer points into a region reserved by us.
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Commit from a region
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// Commit the `blocks` in `region` at `idx` and `bitidx` of a given `size`.
|
||||
// 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, 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);
|
||||
mi_assert_internal((mask & mi_atomic_read_relaxed(®ion->map)) == mask);
|
||||
mi_assert_internal(®ions[idx] == region);
|
||||
|
||||
// ensure the region is reserved
|
||||
mi_region_info_t info = mi_atomic_read(®ion->info);
|
||||
if (info == 0)
|
||||
{
|
||||
bool region_commit = mi_option_is_enabled(mi_option_eager_region_commit);
|
||||
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
|
||||
size_t map;
|
||||
do {
|
||||
map = mi_atomic_read_relaxed(®ion->map);
|
||||
} while (!mi_atomic_cas_weak(®ion->map, map & ~mask, map));
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the newly allocated region
|
||||
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);
|
||||
}
|
||||
else {
|
||||
// failed, another thread allocated just before us!
|
||||
// we assign it to a later slot instead (up to 4 tries).
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (start != NULL) {
|
||||
// free it if we didn't succeed to save it to some other region
|
||||
_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);
|
||||
}
|
||||
}
|
||||
mi_assert_internal(info == mi_atomic_read(®ion->info));
|
||||
mi_assert_internal(info != 0);
|
||||
|
||||
// Commit the blocks to memory
|
||||
bool region_is_committed = false;
|
||||
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;
|
||||
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
|
||||
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)
|
||||
*commit = true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use bit scan forward to quickly find the first zero bit if it is available
|
||||
#if defined(_MSC_VER)
|
||||
#define MI_HAVE_BITSCAN
|
||||
#include <intrin.h>
|
||||
static inline size_t mi_bsf(uintptr_t x) {
|
||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
||||
DWORD idx;
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
_BitScanForward64(&idx, x);
|
||||
#else
|
||||
_BitScanForward(&idx, x);
|
||||
#endif
|
||||
return idx;
|
||||
}
|
||||
static inline size_t mi_bsr(uintptr_t x) {
|
||||
if (x==0) return 8*MI_INTPTR_SIZE;
|
||||
DWORD idx;
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
_BitScanReverse64(&idx, x);
|
||||
#else
|
||||
_BitScanReverse(&idx, x);
|
||||
#endif
|
||||
return idx;
|
||||
}
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define MI_HAVE_BITSCAN
|
||||
static inline size_t mi_bsf(uintptr_t x) {
|
||||
return (x==0 ? 8*MI_INTPTR_SIZE : __builtin_ctzl(x));
|
||||
}
|
||||
static inline size_t mi_bsr(uintptr_t x) {
|
||||
return (x==0 ? 8*MI_INTPTR_SIZE : (8*MI_INTPTR_SIZE - 1) - __builtin_clzl(x));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate `blocks` in a `region` at `idx` of a given `size`.
|
||||
// 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, 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);
|
||||
|
||||
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
|
||||
#else
|
||||
size_t bitidx = 0; // otherwise start at 0
|
||||
#endif
|
||||
uintptr_t m = (mask << bitidx); // invariant: m == mask shifted by bitidx
|
||||
|
||||
// scan linearly for a free range of zero bits
|
||||
while(bitidx <= bitidx_max) {
|
||||
if ((map & m) == 0) { // are the mask bits free at bitidx?
|
||||
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)) { // TODO: use strong cas here?
|
||||
// no success, another thread claimed concurrently.. keep going
|
||||
map = mi_atomic_read(®ion->map);
|
||||
continue;
|
||||
}
|
||||
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, is_zero, p, id, tld);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// on to the next bit range
|
||||
#ifdef MI_HAVE_BITSCAN
|
||||
size_t shift = (blocks == 1 ? 1 : mi_bsr(map & m) - bitidx + 1);
|
||||
mi_assert_internal(shift > 0 && shift <= blocks);
|
||||
#else
|
||||
size_t shift = 1;
|
||||
#endif
|
||||
bitidx += shift;
|
||||
m <<= shift;
|
||||
}
|
||||
}
|
||||
// no error, but also no bits found
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to allocate `blocks` in a `region` at `idx` of a given `size`. Does a quick check before trying to claim.
|
||||
// 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, 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);
|
||||
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 || *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 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) || (*allow_large || !is_large)); // Todo: test with one bitmap operation?
|
||||
}
|
||||
if (ok) {
|
||||
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
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Allocation
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// 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, 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`
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// always round size to OS page size multiple (so commit/decommit go over the entire range)
|
||||
// TODO: use large OS page size here?
|
||||
size = _mi_align_up(size, _mi_os_page_size());
|
||||
|
||||
// calculate the number of needed blocks
|
||||
size_t blocks = mi_region_block_count(size);
|
||||
mi_assert_internal(blocks > 0 && blocks <= 8*MI_INTPTR_SIZE);
|
||||
|
||||
// find a range of free blocks
|
||||
void* p = NULL;
|
||||
size_t count = mi_atomic_read(®ions_count);
|
||||
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
|
||||
if (p != NULL) break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
// no free range in existing regions -- try to extend beyond the count.. but at most 8 regions
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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? currently not used as we use first-fit
|
||||
}
|
||||
|
||||
mi_assert_internal( p == NULL || (uintptr_t)p % alignment == 0);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Free
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// Free previously allocated memory with a given id.
|
||||
void _mi_mem_free(void* p, size_t size, size_t id, mi_stats_t* stats) {
|
||||
mi_assert_internal(size > 0 && stats != NULL);
|
||||
if (p==NULL) return;
|
||||
if (size==0) return;
|
||||
if (id == SIZE_MAX) {
|
||||
// was a direct OS allocation, pass through
|
||||
_mi_os_free(p, size, stats);
|
||||
}
|
||||
else {
|
||||
// allocated in a region
|
||||
mi_assert_internal(size <= MI_REGION_MAX_ALLOC_SIZE); if (size > MI_REGION_MAX_ALLOC_SIZE) return;
|
||||
// we can align the size up to page size (as we allocate that way too)
|
||||
// this ensures we fully commit/decommit/reset
|
||||
size = _mi_align_up(size, _mi_os_page_size());
|
||||
size_t idx = (id / MI_REGION_MAP_BITS);
|
||||
size_t bitidx = (id % MI_REGION_MAP_BITS);
|
||||
size_t blocks = mi_region_block_count(size);
|
||||
size_t mask = mi_region_block_mask(blocks, bitidx);
|
||||
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?
|
||||
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?
|
||||
mi_assert_internal(bitidx + blocks <= MI_REGION_MAP_BITS);
|
||||
if (blocks_start != p || bitidx + blocks > MI_REGION_MAP_BITS) return; // or `abort`?
|
||||
|
||||
// decommit (or reset) the blocks to reduce the working set.
|
||||
// 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 (!is_large) {
|
||||
if (mi_option_is_enabled(mi_option_segment_reset)) {
|
||||
if (!is_eager_committed && // cannot reset large pages
|
||||
(mi_option_is_enabled(mi_option_eager_commit) || // cannot reset halfway committed segments, use `option_page_reset` instead
|
||||
mi_option_is_enabled(mi_option_reset_decommits))) // but we can decommit halfway committed segments
|
||||
{
|
||||
_mi_os_reset(p, size, stats);
|
||||
//_mi_os_decommit(p, size, stats); // todo: and clear dirty bits?
|
||||
}
|
||||
}
|
||||
}
|
||||
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?
|
||||
|
||||
// and unclaim
|
||||
uintptr_t map;
|
||||
uintptr_t newmap;
|
||||
do {
|
||||
map = mi_atomic_read_relaxed(®ion->map);
|
||||
newmap = map & ~mask;
|
||||
} while (!mi_atomic_cas_weak(®ion->map, newmap, map));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
collection
|
||||
-----------------------------------------------------------------------------*/
|
||||
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) {
|
||||
// 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 (unless it was huge reserved)
|
||||
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_ex(start, MI_REGION_SIZE, is_eager_committed, stats);
|
||||
}
|
||||
// and release
|
||||
mi_atomic_write(®ion->info,0);
|
||||
mi_atomic_write(®ion->map,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Other
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
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) {
|
||||
return _mi_os_decommit(p, size, stats);
|
||||
}
|
||||
|
||||
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, 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) {
|
||||
return _mi_os_protect(p, size);
|
||||
}
|
||||
|
||||
bool _mi_mem_unprotect(void* p, size_t size) {
|
||||
return _mi_os_unprotect(p, size);
|
||||
}
|
140
src/options.c
140
src/options.c
@ -28,7 +28,7 @@ int mi_version(void) mi_attr_noexcept {
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Options
|
||||
// These can be accessed by multiple threads and may be
|
||||
// These can be accessed by multiple threads and may be
|
||||
// concurrently initialized, but an initializing data race
|
||||
// is ok since they resolve to the same value.
|
||||
// --------------------------------------------------------
|
||||
@ -56,22 +56,25 @@ static mi_option_desc_t options[_mi_option_last] =
|
||||
{ 0, UNINIT, MI_OPTION(verbose) },
|
||||
|
||||
// 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?
|
||||
{ 0, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...)
|
||||
{ 1, UNINIT, MI_OPTION(eager_commit) }, // commit on demand
|
||||
#if defined(_WIN32) || (MI_INTPTR_SIZE <= 4) // and other OS's without overcommit?
|
||||
{ 0, UNINIT, MI_OPTION(eager_region_commit) },
|
||||
{ 1, UNINIT, MI_OPTION(reset_decommits) }, // reset decommits memory
|
||||
#else
|
||||
{ 1, UNINIT, MI_OPTION(eager_region_commit) },
|
||||
{ 0, UNINIT, MI_OPTION(reset_decommits) }, // reset uses MADV_FREE/MADV_DONTNEED
|
||||
#endif
|
||||
{ 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(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
|
||||
{ 1, UNINIT, MI_OPTION(page_reset) }, // reset page memory on free
|
||||
{ 0, UNINIT, MI_OPTION(abandoned_page_reset) },// reset free page memory when a thread terminates
|
||||
{ 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free (needs eager commit)
|
||||
{ 1, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
|
||||
{ 100, UNINIT, MI_OPTION(reset_delay) }, // reset delay in milli-seconds
|
||||
{ 0, UNINIT, MI_OPTION(use_numa_nodes) }, // 0 = use available numa nodes, otherwise use at most N nodes.
|
||||
{ 100, UNINIT, MI_OPTION(os_tag) }, // only apple specific for now but might serve more or less related purpose
|
||||
{ 16, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output
|
||||
{ 16, UNINIT, MI_OPTION(max_errors) } // maximum errors that are output
|
||||
};
|
||||
|
||||
static void mi_option_init(mi_option_desc_t* desc);
|
||||
@ -96,7 +99,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);
|
||||
mi_option_init(desc);
|
||||
}
|
||||
return desc->value;
|
||||
}
|
||||
@ -138,9 +141,10 @@ void mi_option_disable(mi_option_t option) {
|
||||
}
|
||||
|
||||
|
||||
static void mi_out_stderr(const char* msg) {
|
||||
static void mi_out_stderr(const char* msg, void* arg) {
|
||||
UNUSED(arg);
|
||||
#ifdef _WIN32
|
||||
// on windows with redirection, the C runtime cannot handle locale dependent output
|
||||
// on windows with redirection, the C runtime cannot handle locale dependent output
|
||||
// after the main thread closes so we use direct console output.
|
||||
if (!_mi_preloading()) { _cputs(msg); }
|
||||
#else
|
||||
@ -158,13 +162,14 @@ static void mi_out_stderr(const char* msg) {
|
||||
static char out_buf[MI_MAX_DELAY_OUTPUT+1];
|
||||
static _Atomic(uintptr_t) out_len;
|
||||
|
||||
static void mi_out_buf(const char* msg) {
|
||||
static void mi_out_buf(const char* msg, void* arg) {
|
||||
UNUSED(arg);
|
||||
if (msg==NULL) 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);
|
||||
uintptr_t start = mi_atomic_add(&out_len, n);
|
||||
if (start >= MI_MAX_DELAY_OUTPUT) return;
|
||||
// check bound
|
||||
if (start+n >= MI_MAX_DELAY_OUTPUT) {
|
||||
@ -173,25 +178,25 @@ static void mi_out_buf(const char* msg) {
|
||||
memcpy(&out_buf[start], msg, n);
|
||||
}
|
||||
|
||||
static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf) {
|
||||
static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) {
|
||||
if (out==NULL) return;
|
||||
// claim (if `no_more_buf == true`, no more output will be added after this point)
|
||||
size_t count = mi_atomic_addu(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1));
|
||||
size_t count = mi_atomic_add(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1));
|
||||
// and output the current contents
|
||||
if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT;
|
||||
out_buf[count] = 0;
|
||||
out(out_buf);
|
||||
out(out_buf,arg);
|
||||
if (!no_more_buf) {
|
||||
out_buf[count] = '\n'; // if continue with the buffer, insert a newline
|
||||
out_buf[count] = '\n'; // if continue with the buffer, insert a newline
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Once this module is loaded, switch to this routine
|
||||
// which 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);
|
||||
static void mi_out_buf_stderr(const char* msg, void* arg) {
|
||||
mi_out_stderr(msg,arg);
|
||||
mi_out_buf(msg,arg);
|
||||
}
|
||||
|
||||
|
||||
@ -204,60 +209,65 @@ static void mi_out_buf_stderr(const char* msg) {
|
||||
// For now, don't register output from multiple threads.
|
||||
#pragma warning(suppress:4180)
|
||||
static mi_output_fun* volatile mi_out_default; // = NULL
|
||||
static volatile _Atomic(void*) mi_out_arg; // = NULL
|
||||
|
||||
static mi_output_fun* mi_out_get_default(void) {
|
||||
static mi_output_fun* mi_out_get_default(void** parg) {
|
||||
if (parg != NULL) { *parg = mi_atomic_read_ptr(void,&mi_out_arg); }
|
||||
mi_output_fun* out = mi_out_default;
|
||||
return (out == NULL ? &mi_out_buf : out);
|
||||
}
|
||||
|
||||
void mi_register_output(mi_output_fun* out) mi_attr_noexcept {
|
||||
void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept {
|
||||
mi_out_default = (out == NULL ? &mi_out_stderr : out); // stop using the delayed output buffer
|
||||
if (out!=NULL) mi_out_buf_flush(out,true); // output all the delayed output now
|
||||
mi_atomic_write_ptr(void,&mi_out_arg, arg);
|
||||
if (out!=NULL) mi_out_buf_flush(out,true,arg); // output all the delayed output now
|
||||
}
|
||||
|
||||
// add stderr to the delayed output after the module is loaded
|
||||
static void mi_add_stderr_output() {
|
||||
mi_out_buf_flush(&mi_out_stderr, false); // flush current contents to stderr
|
||||
mi_out_default = &mi_out_buf_stderr; // and add stderr to the delayed output
|
||||
mi_assert_internal(mi_out_default == NULL);
|
||||
mi_out_buf_flush(&mi_out_stderr, false, NULL); // flush current contents to stderr
|
||||
mi_out_default = &mi_out_buf_stderr; // and add stderr to the delayed output
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// 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
|
||||
|
||||
// When overriding malloc, we may recurse into mi_vfprintf if an allocation
|
||||
// inside the C runtime causes another message.
|
||||
static mi_decl_thread bool recurse = false;
|
||||
|
||||
void _mi_fputs(mi_output_fun* out, const char* prefix, const char* message) {
|
||||
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message) {
|
||||
if (recurse) return;
|
||||
if (out==NULL || (FILE*)out==stdout || (FILE*)out==stderr) out = mi_out_get_default();
|
||||
if (out==NULL || (FILE*)out==stdout || (FILE*)out==stderr) { // TODO: use mi_out_stderr for stderr?
|
||||
out = mi_out_get_default(&arg);
|
||||
}
|
||||
recurse = true;
|
||||
if (prefix != NULL) out(prefix);
|
||||
out(message);
|
||||
if (prefix != NULL) out(prefix,arg);
|
||||
out(message,arg);
|
||||
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( mi_output_fun* out, const char* prefix, const char* fmt, va_list args ) {
|
||||
static void mi_vfprintf( mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args ) {
|
||||
char buf[512];
|
||||
if (fmt==NULL) return;
|
||||
if (recurse) return;
|
||||
recurse = true;
|
||||
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
||||
recurse = false;
|
||||
_mi_fputs(out,prefix,buf);
|
||||
_mi_fputs(out,arg,prefix,buf);
|
||||
}
|
||||
|
||||
|
||||
void _mi_fprintf( mi_output_fun* out, const char* fmt, ... ) {
|
||||
void _mi_fprintf( mi_output_fun* out, void* arg, const char* fmt, ... ) {
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(out,NULL,fmt,args);
|
||||
mi_vfprintf(out,arg,NULL,fmt,args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -265,7 +275,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(NULL, "mimalloc: ", fmt, args);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: ", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -273,18 +283,14 @@ 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(NULL, "mimalloc: ", fmt, args);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: ", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void _mi_error_message(const char* fmt, ...) {
|
||||
static void mi_show_error_message(const char* fmt, va_list args) {
|
||||
if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return;
|
||||
if (mi_atomic_increment(&error_count) > mi_max_error_count) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(NULL, "mimalloc: error: ", fmt, args);
|
||||
va_end(args);
|
||||
mi_assert(false);
|
||||
mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args);
|
||||
}
|
||||
|
||||
void _mi_warning_message(const char* fmt, ...) {
|
||||
@ -292,26 +298,52 @@ void _mi_warning_message(const char* fmt, ...) {
|
||||
if (mi_atomic_increment(&error_count) > mi_max_error_count) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(NULL, "mimalloc: warning: ", fmt, args);
|
||||
mi_vfprintf(NULL, 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(NULL,"mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion);
|
||||
_mi_fprintf(NULL, NULL, "mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
mi_attr_noreturn void _mi_fatal_error(const char* fmt, ...) {
|
||||
// --------------------------------------------------------
|
||||
// Errors
|
||||
// --------------------------------------------------------
|
||||
|
||||
static mi_error_fun* volatile mi_error_handler; // = NULL
|
||||
static volatile _Atomic(void*) mi_error_arg; // = NULL
|
||||
|
||||
static void mi_error_default(int err) {
|
||||
UNUSED(err);
|
||||
#if (MI_SECURE>0)
|
||||
if (err==EFAULT) { // abort on serious errors in secure mode (corrupted meta-data)
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mi_register_error(mi_error_fun* fun, void* arg) {
|
||||
mi_error_handler = fun; // can be NULL
|
||||
mi_atomic_write_ptr(void,&mi_error_arg, arg);
|
||||
}
|
||||
|
||||
void _mi_error_message(int err, const char* fmt, ...) {
|
||||
// show detailed error message
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
mi_vfprintf(NULL, "mimalloc: fatal: ", fmt, args);
|
||||
mi_show_error_message(fmt, args);
|
||||
va_end(args);
|
||||
#if (MI_SECURE>=0)
|
||||
abort();
|
||||
#endif
|
||||
// and call the error handler which may abort (or return normally)
|
||||
if (mi_error_handler != NULL) {
|
||||
mi_error_handler(err, mi_atomic_read_ptr(void,&mi_error_arg));
|
||||
}
|
||||
else {
|
||||
mi_error_default(err);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
@ -339,7 +371,7 @@ static void mi_strlcat(char* dest, const char* src, size_t dest_size) {
|
||||
#include <windows.h>
|
||||
static bool mi_getenv(const char* name, char* result, size_t result_size) {
|
||||
result[0] = 0;
|
||||
size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size);
|
||||
size_t len = GetEnvironmentVariableA(name, result, (DWORD)result_size);
|
||||
return (len > 0 && len < result_size);
|
||||
}
|
||||
#else
|
||||
@ -365,7 +397,11 @@ static bool mi_getenv(const char* name, char* result, size_t result_size) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
static void mi_option_init(mi_option_desc_t* desc) {
|
||||
static void mi_option_init(mi_option_desc_t* desc) {
|
||||
#ifndef _WIN32
|
||||
// cannot call getenv() when still initializing the C runtime.
|
||||
if (_mi_preloading()) return;
|
||||
#endif
|
||||
// Read option value from the environment
|
||||
char buf[64+1];
|
||||
mi_strlcpy(buf, "mimalloc_", sizeof(buf));
|
||||
|
485
src/os.c
485
src/os.c
@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#include "mimalloc-atomic.h"
|
||||
|
||||
#include <string.h> // strerror
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
@ -36,8 +36,6 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
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);
|
||||
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);
|
||||
@ -150,7 +148,7 @@ void _mi_os_init(void) {
|
||||
FreeLibrary(hDll);
|
||||
}
|
||||
hDll = LoadLibrary(TEXT("ntdll.dll"));
|
||||
if (hDll != NULL) {
|
||||
if (hDll != NULL) {
|
||||
pNtAllocateVirtualMemoryEx = (PNtAllocateVirtualMemoryEx)(void (*)(void))GetProcAddress(hDll, "NtAllocateVirtualMemoryEx");
|
||||
FreeLibrary(hDll);
|
||||
}
|
||||
@ -171,9 +169,7 @@ void _mi_os_init() {
|
||||
os_page_size = (size_t)result;
|
||||
os_alloc_granularity = os_page_size;
|
||||
}
|
||||
if (mi_option_is_enabled(mi_option_large_os_pages)) {
|
||||
large_os_page_size = (1UL << 21); // 2MiB
|
||||
}
|
||||
large_os_page_size = 2*MiB; // TODO: can we query the OS for this?
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -184,7 +180,7 @@ void _mi_os_init() {
|
||||
|
||||
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;
|
||||
if (addr == NULL || size == 0) return true; // || _mi_os_is_huge_reserved(addr)
|
||||
bool err = false;
|
||||
#if defined(_WIN32)
|
||||
err = (VirtualFree(addr, 0, MEM_RELEASE) == 0);
|
||||
@ -209,31 +205,6 @@ 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)
|
||||
// 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_RESERVE) != 0
|
||||
&& (addr != NULL || try_alignment == 0 || try_alignment % _mi_os_page_size() == 0)
|
||||
&& pNtAllocateVirtualMemoryEx != NULL)
|
||||
{
|
||||
#ifndef MEM_EXTENDED_PARAMETER_NONPAGED_HUGE
|
||||
#define MEM_EXTENDED_PARAMETER_NONPAGED_HUGE (0x10)
|
||||
#endif
|
||||
MEM_EXTENDED_PARAMETER param = { 0, 0 };
|
||||
param.Type = 5; // == MemExtendedParameterAttributeFlags;
|
||||
param.ULong64 = MEM_EXTENDED_PARAMETER_NONPAGED_HUGE;
|
||||
SIZE_T psize = size;
|
||||
void* base = addr;
|
||||
NTSTATUS err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags, PAGE_READWRITE, ¶m, 1);
|
||||
if (err == 0) {
|
||||
return base;
|
||||
}
|
||||
else {
|
||||
// else fall back to regular large OS pages
|
||||
_mi_warning_message("unable to allocate huge (1GiB) page, trying large (2MiB) pages instead (error 0x%lx)\n", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (MI_INTPTR_SIZE >= 8)
|
||||
// on 64-bit systems, try to use the virtual address area after 4TiB for 4MiB aligned allocations
|
||||
void* hint;
|
||||
@ -327,7 +298,10 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
#if !defined(MAP_ANONYMOUS)
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
#if !defined(MAP_NORESERVE)
|
||||
#define MAP_NORESERVE 0
|
||||
#endif
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
|
||||
int fd = -1;
|
||||
#if defined(MAP_ALIGNED) // BSD
|
||||
if (try_alignment > 0) {
|
||||
@ -357,7 +331,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
mi_atomic_cas_weak(&large_page_try_ok, try_ok - 1, try_ok);
|
||||
}
|
||||
else {
|
||||
int lflags = flags;
|
||||
int lflags = flags & ~MAP_NORESERVE; // using NORESERVE on huge pages seems to fail on Linux
|
||||
int lfd = fd;
|
||||
#ifdef MAP_ALIGNED_SUPER
|
||||
lflags |= MAP_ALIGNED_SUPER;
|
||||
@ -366,7 +340,8 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
lflags |= MAP_HUGETLB;
|
||||
#endif
|
||||
#ifdef MAP_HUGE_1GB
|
||||
if ((size % ((uintptr_t)1 << 30)) == 0) {
|
||||
static bool mi_huge_pages_available = true;
|
||||
if ((size % GiB) == 0 && mi_huge_pages_available) {
|
||||
lflags |= MAP_HUGE_1GB;
|
||||
}
|
||||
else
|
||||
@ -385,6 +360,7 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
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_huge_pages_available = false; // don't try huge 1GiB pages again
|
||||
_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);
|
||||
@ -402,10 +378,10 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
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
|
||||
// transparent huge pages (TPH). It is not required to call `madvise` with MADV_HUGE
|
||||
// transparent huge pages (THP). It is not required to call `madvise` with MADV_HUGE
|
||||
// though since properly aligned allocations will already use large pages if available
|
||||
// in that case -- in particular for our large regions (in `memory.c`).
|
||||
// However, some systems only allow TPH if called with explicit `madvise`, so
|
||||
// However, some systems only allow THP if called with explicit `madvise`, so
|
||||
// when large OS pages are enabled for mimalloc, we call `madvice` anyways.
|
||||
if (allow_large && use_large_os_page(size, try_alignment)) {
|
||||
if (madvise(p, size, MADV_HUGEPAGE) == 0) {
|
||||
@ -421,20 +397,20 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro
|
||||
// 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;
|
||||
static volatile mi_decl_cache_align _Atomic(uintptr_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);
|
||||
uintptr_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
|
||||
uintptr_t init = ((uintptr_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
|
||||
uintptr_t r = _mi_heap_random_next(mi_get_default_heap());
|
||||
init = init + (MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)); // (randomly 20 bits)*4MiB == 0 to 4TiB
|
||||
#endif
|
||||
mi_atomic_cas_strong(mi_atomic_cast(uintptr_t, &aligned_base), init, hint + size);
|
||||
mi_atomic_cas_strong(&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;
|
||||
@ -620,15 +596,27 @@ static void* mi_os_page_align_area_conservative(void* addr, size_t size, size_t*
|
||||
return mi_os_page_align_areax(true, addr, size, newsize);
|
||||
}
|
||||
|
||||
static void mi_mprotect_hint(int err) {
|
||||
#if defined(MI_OS_USE_MMAP) && (MI_SECURE>=2) // guard page around every mimalloc page
|
||||
if (err == ENOMEM) {
|
||||
_mi_warning_message("the previous warning may have been caused by a low memory map limit.\n"
|
||||
" On Linux this is controlled by the vm.max_map_count. For example:\n"
|
||||
" > sudo sysctl -w vm.max_map_count=262144\n");
|
||||
}
|
||||
#else
|
||||
UNUSED(err);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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, bool* is_zero, mi_stats_t* stats) {
|
||||
// page align in the range, commit liberally, decommit conservative
|
||||
*is_zero = false;
|
||||
if (is_zero != NULL) { *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;
|
||||
if (csize == 0) return true; // || _mi_os_is_huge_reserved(addr))
|
||||
int err = 0;
|
||||
if (commit) {
|
||||
_mi_stat_increase(&stats->committed, csize);
|
||||
@ -651,31 +639,42 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ
|
||||
}
|
||||
#elif defined(__wasi__)
|
||||
// WebAssembly guests can't control memory protection
|
||||
#elif defined(MAP_FIXED)
|
||||
if (!commit) {
|
||||
// use mmap with MAP_FIXED to discard the existing memory (and reduce commit charge)
|
||||
void* p = mmap(start, csize, PROT_NONE, (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE), -1, 0);
|
||||
if (p != start) { err = errno; }
|
||||
}
|
||||
else {
|
||||
// for commit, just change the protection
|
||||
err = mprotect(start, csize, (PROT_READ | PROT_WRITE));
|
||||
if (err != 0) { err = errno; }
|
||||
}
|
||||
#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);
|
||||
_mi_warning_message("%s error: start: %p, csize: 0x%x, err: %i\n", commit ? "commit" : "decommit", start, csize, err);
|
||||
mi_mprotect_hint(err);
|
||||
}
|
||||
mi_assert_internal(err == 0);
|
||||
return (err == 0);
|
||||
}
|
||||
|
||||
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);
|
||||
return mi_os_commitx(addr, size, true, false /* liberal */, is_zero, stats);
|
||||
}
|
||||
|
||||
bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats) {
|
||||
bool is_zero;
|
||||
return mi_os_commitx(addr, size, false, true /* conservative? */, &is_zero, stats);
|
||||
return mi_os_commitx(addr, size, false, true /* conservative */, &is_zero, 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);
|
||||
return mi_os_commitx(addr, size, true, true /* conservative */, is_zero, stats);
|
||||
}
|
||||
|
||||
|
||||
// Signal to the OS that the address range is no longer in use
|
||||
// but may be used later again. This will release physical memory
|
||||
// pages and reduce swapping while keeping the memory committed.
|
||||
@ -684,7 +683,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) return true; // || _mi_os_is_huge_reserved(addr)
|
||||
if (reset) _mi_stat_increase(&stats->reset, csize);
|
||||
else _mi_stat_decrease(&stats->reset, csize);
|
||||
if (!reset) return true; // nothing to do on unreset!
|
||||
@ -720,7 +719,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats)
|
||||
int err = madvise(start, csize, MADV_DONTNEED);
|
||||
#endif
|
||||
if (err != 0) {
|
||||
_mi_warning_message("madvise reset error: start: 0x%p, csize: 0x%x, errno: %i\n", start, csize, errno);
|
||||
_mi_warning_message("madvise reset error: start: %p, csize: 0x%x, errno: %i\n", start, csize, errno);
|
||||
}
|
||||
//mi_assert(err == 0);
|
||||
if (err != 0) return false;
|
||||
@ -734,7 +733,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats)
|
||||
// We page align to a conservative area inside the range to reset.
|
||||
bool _mi_os_reset(void* addr, size_t size, mi_stats_t* stats) {
|
||||
if (mi_option_is_enabled(mi_option_reset_decommits)) {
|
||||
return _mi_os_decommit(addr,size,stats);
|
||||
return _mi_os_decommit(addr, size, stats);
|
||||
}
|
||||
else {
|
||||
return mi_os_resetx(addr, size, true, stats);
|
||||
@ -758,9 +757,11 @@ 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");
|
||||
}
|
||||
*/
|
||||
int err = 0;
|
||||
#ifdef _WIN32
|
||||
DWORD oldprotect = 0;
|
||||
@ -773,7 +774,8 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) {
|
||||
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);
|
||||
_mi_warning_message("mprotect error: start: %p, csize: 0x%x, err: %i\n", start, csize, err);
|
||||
mi_mprotect_hint(err);
|
||||
}
|
||||
return (err == 0);
|
||||
}
|
||||
@ -810,140 +812,267 @@ 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.
|
||||
Support for allocating huge OS pages (1Gib) that are reserved up-front
|
||||
and possibly associated with a specific NUMA node. (use `numa_node>=0`)
|
||||
-----------------------------------------------------------------------------*/
|
||||
#define MI_HUGE_OS_PAGE_SIZE ((size_t)1 << 30) // 1GiB
|
||||
#define MI_HUGE_OS_PAGE_SIZE (GiB)
|
||||
|
||||
typedef struct mi_huge_info_s {
|
||||
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) };
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void* _mi_os_try_alloc_from_huge_reserved(size_t size, size_t try_alignment)
|
||||
#if defined(WIN32) && (MI_INTPTR_SIZE >= 8)
|
||||
static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node)
|
||||
{
|
||||
// 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;
|
||||
if (mi_atomic_read(&os_huge_reserved.used) >= mi_atomic_read(&os_huge_reserved.reserved)) return NULL; // already full
|
||||
mi_assert_internal(size%GiB == 0);
|
||||
mi_assert_internal(addr != NULL);
|
||||
const DWORD flags = MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE;
|
||||
|
||||
// always aligned
|
||||
mi_assert_internal(mi_atomic_read(&os_huge_reserved.used) % MI_SEGMENT_SIZE == 0 );
|
||||
mi_assert_internal( (uintptr_t)mi_atomic_read_ptr(&os_huge_reserved.start) % MI_SEGMENT_SIZE == 0 );
|
||||
mi_win_enable_large_os_pages();
|
||||
|
||||
// try to reserve space
|
||||
size_t base = mi_atomic_addu( &os_huge_reserved.used, size );
|
||||
if ((base + size) > os_huge_reserved.reserved) {
|
||||
// "free" our over-allocation
|
||||
mi_atomic_subu( &os_huge_reserved.used, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// success!
|
||||
uint8_t* p = (uint8_t*)mi_atomic_read_ptr(&os_huge_reserved.start) + base;
|
||||
mi_assert_internal( (uintptr_t)p % MI_SEGMENT_SIZE == 0 );
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
static void mi_os_free_huge_reserved() {
|
||||
uint8_t* addr = os_huge_reserved.start;
|
||||
size_t total = os_huge_reserved.reserved;
|
||||
os_huge_reserved.reserved = 0;
|
||||
os_huge_reserved.start = NULL;
|
||||
for( size_t current = 0; current < total; current += MI_HUGE_OS_PAGE_SIZE) {
|
||||
_mi_os_free(addr + current, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#if !(MI_INTPTR_SIZE >= 8 && (defined(_WIN32) || defined(MI_OS_USE_MMAP)))
|
||||
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;
|
||||
}
|
||||
#else
|
||||
int mi_reserve_huge_os_pages( size_t pages, double max_secs, size_t* pages_reserved ) mi_attr_noexcept
|
||||
{
|
||||
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 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_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
|
||||
// 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* addr = start; // current top of the allocations
|
||||
for (size_t page = 0; page < pages; page++, addr += MI_HUGE_OS_PAGE_SIZE ) {
|
||||
// allocate a page
|
||||
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);
|
||||
#else
|
||||
// always fail
|
||||
#if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS)
|
||||
MEM_EXTENDED_PARAMETER params[3] = { {0,0},{0,0},{0,0} };
|
||||
// on modern Windows try use NtAllocateVirtualMemoryEx for 1GiB huge pages
|
||||
static bool mi_huge_pages_available = true;
|
||||
if (pNtAllocateVirtualMemoryEx != NULL && mi_huge_pages_available) {
|
||||
#ifndef MEM_EXTENDED_PARAMETER_NONPAGED_HUGE
|
||||
#define MEM_EXTENDED_PARAMETER_NONPAGED_HUGE (0x10)
|
||||
#endif
|
||||
|
||||
// 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 );
|
||||
}
|
||||
else {
|
||||
#ifdef _WIN32
|
||||
int err = GetLastError();
|
||||
#else
|
||||
int err = errno;
|
||||
#endif
|
||||
_mi_warning_message("could not allocate huge page %zu at 0x%p, error: %i\n", page, addr, err);
|
||||
}
|
||||
return ENOMEM;
|
||||
params[0].Type = 5; // == MemExtendedParameterAttributeFlags;
|
||||
params[0].ULong64 = MEM_EXTENDED_PARAMETER_NONPAGED_HUGE;
|
||||
ULONG param_count = 1;
|
||||
if (numa_node >= 0) {
|
||||
param_count++;
|
||||
params[1].Type = MemExtendedParameterNumaNode;
|
||||
params[1].ULong = (unsigned)numa_node;
|
||||
}
|
||||
// success, record it
|
||||
if (page==0) {
|
||||
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);
|
||||
SIZE_T psize = size;
|
||||
void* base = addr;
|
||||
NTSTATUS err = (*pNtAllocateVirtualMemoryEx)(GetCurrentProcess(), &base, &psize, flags, PAGE_READWRITE, params, param_count);
|
||||
if (err == 0 && base != NULL) {
|
||||
return base;
|
||||
}
|
||||
else {
|
||||
mi_atomic_addu(&os_huge_reserved.reserved,MI_HUGE_OS_PAGE_SIZE);
|
||||
}
|
||||
_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 ETIMEDOUT;
|
||||
if (page >= 1) {
|
||||
double estimate = ((elapsed / (double)(page+1)) * (double)pages);
|
||||
if (estimate > 1.5*max_secs) return ETIMEDOUT; // seems like we are going to timeout
|
||||
// fall back to regular large pages
|
||||
mi_huge_pages_available = false; // don't try further huge pages
|
||||
_mi_warning_message("unable to allocate using huge (1GiB) pages, trying large (2MiB) pages instead (status 0x%lx)\n", err);
|
||||
}
|
||||
}
|
||||
_mi_verbose_message("reserved %zu huge pages\n", pages);
|
||||
// on modern Windows try use VirtualAlloc2 for numa aware large OS page allocation
|
||||
if (pVirtualAlloc2 != NULL && numa_node >= 0) {
|
||||
params[0].Type = MemExtendedParameterNumaNode;
|
||||
params[0].ULong = (unsigned)numa_node;
|
||||
return (*pVirtualAlloc2)(GetCurrentProcess(), addr, size, flags, PAGE_READWRITE, params, 1);
|
||||
}
|
||||
#endif
|
||||
// otherwise use regular virtual alloc on older windows
|
||||
return VirtualAlloc(addr, size, flags, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
#elif defined(MI_OS_USE_MMAP) && (MI_INTPTR_SIZE >= 8)
|
||||
#include <sys/syscall.h>
|
||||
#ifndef MPOL_PREFERRED
|
||||
#define MPOL_PREFERRED 1
|
||||
#endif
|
||||
#if defined(SYS_mbind)
|
||||
static long mi_os_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) {
|
||||
return syscall(SYS_mbind, start, len, mode, nmask, maxnode, flags);
|
||||
}
|
||||
#else
|
||||
static long mi_os_mbind(void* start, unsigned long len, unsigned long mode, const unsigned long* nmask, unsigned long maxnode, unsigned flags) {
|
||||
UNUSED(start); UNUSED(len); UNUSED(mode); UNUSED(nmask); UNUSED(maxnode); UNUSED(flags);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) {
|
||||
mi_assert_internal(size%GiB == 0);
|
||||
bool is_large = true;
|
||||
void* p = mi_unix_mmap(addr, size, MI_SEGMENT_SIZE, PROT_READ | PROT_WRITE, true, true, &is_large);
|
||||
if (p == NULL) return NULL;
|
||||
if (numa_node >= 0 && numa_node < 8*MI_INTPTR_SIZE) { // at most 64 nodes
|
||||
uintptr_t numa_mask = (1UL << numa_node);
|
||||
// TODO: does `mbind` work correctly for huge OS pages? should we
|
||||
// use `set_mempolicy` before calling mmap instead?
|
||||
// see: <https://lkml.org/lkml/2017/2/9/875>
|
||||
long err = mi_os_mbind(p, size, MPOL_PREFERRED, &numa_mask, 8*MI_INTPTR_SIZE, 0);
|
||||
if (err != 0) {
|
||||
_mi_warning_message("failed to bind huge (1GiB) pages to NUMA node %d: %s\n", numa_node, strerror(errno));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MI_INTPTR_SIZE >= 8)
|
||||
// To ensure proper alignment, use our own area for huge OS pages
|
||||
static mi_decl_cache_align _Atomic(uintptr_t) mi_huge_start; // = 0
|
||||
|
||||
// Claim an aligned address range for huge pages
|
||||
static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) {
|
||||
if (total_size != NULL) *total_size = 0;
|
||||
const size_t size = pages * MI_HUGE_OS_PAGE_SIZE;
|
||||
|
||||
uintptr_t start = 0;
|
||||
uintptr_t end = 0;
|
||||
uintptr_t expected;
|
||||
do {
|
||||
start = expected = mi_atomic_read_relaxed(&mi_huge_start);
|
||||
if (start == 0) {
|
||||
// Initialize the start address after the 32TiB area
|
||||
start = ((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_heap_random_next(mi_get_default_heap());
|
||||
start = start + ((uintptr_t)MI_HUGE_OS_PAGE_SIZE * ((r>>17) & 0x0FFF)); // (randomly 12bits)*1GiB == between 0 to 4TiB
|
||||
#endif
|
||||
}
|
||||
end = start + size;
|
||||
mi_assert_internal(end % MI_SEGMENT_SIZE == 0);
|
||||
} while (!mi_atomic_cas_strong(&mi_huge_start, end, expected));
|
||||
|
||||
if (total_size != NULL) *total_size = size;
|
||||
return (uint8_t*)start;
|
||||
}
|
||||
#else
|
||||
static uint8_t* mi_os_claim_huge_pages(size_t pages, size_t* total_size) {
|
||||
if (total_size != NULL) *total_size = 0;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate MI_SEGMENT_SIZE aligned huge pages
|
||||
void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_msecs, size_t* pages_reserved, size_t* psize) {
|
||||
if (psize != NULL) *psize = 0;
|
||||
if (pages_reserved != NULL) *pages_reserved = 0;
|
||||
size_t size = 0;
|
||||
uint8_t* start = mi_os_claim_huge_pages(pages, &size);
|
||||
if (start == NULL) return NULL; // or 32-bit systems
|
||||
|
||||
// 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
|
||||
// or to at least allocate as many as available on the system.
|
||||
mi_msecs_t start_t = _mi_clock_start();
|
||||
size_t page;
|
||||
for (page = 0; page < pages; page++) {
|
||||
// allocate a page
|
||||
void* addr = start + (page * MI_HUGE_OS_PAGE_SIZE);
|
||||
void* p = mi_os_alloc_huge_os_pagesx(addr, MI_HUGE_OS_PAGE_SIZE, numa_node);
|
||||
|
||||
// Did we succeed at a contiguous address?
|
||||
if (p != addr) {
|
||||
// no success, issue a warning and break
|
||||
if (p != NULL) {
|
||||
_mi_warning_message("could not allocate contiguous huge page %zu at %p\n", page, addr);
|
||||
_mi_os_free(p, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// success, record it
|
||||
_mi_stat_increase(&_mi_stats_main.committed, MI_HUGE_OS_PAGE_SIZE);
|
||||
_mi_stat_increase(&_mi_stats_main.reserved, MI_HUGE_OS_PAGE_SIZE);
|
||||
|
||||
// check for timeout
|
||||
if (max_msecs > 0) {
|
||||
mi_msecs_t elapsed = _mi_clock_end(start_t);
|
||||
if (page >= 1) {
|
||||
mi_msecs_t estimate = ((elapsed / (page+1)) * pages);
|
||||
if (estimate > 2*max_msecs) { // seems like we are going to timeout, break
|
||||
elapsed = max_msecs + 1;
|
||||
}
|
||||
}
|
||||
if (elapsed > max_msecs) {
|
||||
_mi_warning_message("huge page allocation timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mi_assert_internal(page*MI_HUGE_OS_PAGE_SIZE <= size);
|
||||
if (pages_reserved != NULL) *pages_reserved = page;
|
||||
if (psize != NULL) *psize = page * MI_HUGE_OS_PAGE_SIZE;
|
||||
return (page == 0 ? NULL : start);
|
||||
}
|
||||
|
||||
// free every huge page in a range individually (as we allocated per page)
|
||||
// note: needed with VirtualAlloc but could potentially be done in one go on mmap'd systems.
|
||||
void _mi_os_free_huge_pages(void* p, size_t size, mi_stats_t* stats) {
|
||||
if (p==NULL || size==0) return;
|
||||
uint8_t* base = (uint8_t*)p;
|
||||
while (size >= MI_HUGE_OS_PAGE_SIZE) {
|
||||
_mi_os_free(base, MI_HUGE_OS_PAGE_SIZE, stats);
|
||||
size -= MI_HUGE_OS_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Support NUMA aware allocation
|
||||
-----------------------------------------------------------------------------*/
|
||||
#ifdef WIN32
|
||||
static size_t mi_os_numa_nodex() {
|
||||
PROCESSOR_NUMBER pnum;
|
||||
USHORT numa_node = 0;
|
||||
GetCurrentProcessorNumberEx(&pnum);
|
||||
GetNumaProcessorNodeEx(&pnum,&numa_node);
|
||||
return numa_node;
|
||||
}
|
||||
|
||||
static size_t mi_os_numa_node_countx(void) {
|
||||
ULONG numa_max = 0;
|
||||
GetNumaHighestNodeNumber(&numa_max);
|
||||
return (numa_max + 1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#include <sys/syscall.h> // getcpu
|
||||
#include <stdio.h> // access
|
||||
|
||||
static size_t mi_os_numa_nodex(void) {
|
||||
#ifdef SYS_getcpu
|
||||
unsigned long node = 0;
|
||||
unsigned long ncpu = 0;
|
||||
long err = syscall(SYS_getcpu, &ncpu, &node, NULL);
|
||||
if (err != 0) return 0;
|
||||
return node;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
static size_t mi_os_numa_node_countx(void) {
|
||||
char buf[128];
|
||||
unsigned node = 0;
|
||||
for(node = 0; node < 256; node++) {
|
||||
// enumerate node entries -- todo: it there a more efficient way to do this? (but ensure there is no allocation)
|
||||
snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1);
|
||||
if (access(buf,R_OK) != 0) break;
|
||||
}
|
||||
return (node+1);
|
||||
}
|
||||
#else
|
||||
static size_t mi_os_numa_nodex(void) {
|
||||
return 0;
|
||||
}
|
||||
static size_t mi_os_numa_node_countx(void) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t _mi_numa_node_count = 0; // cache the node count
|
||||
|
||||
size_t _mi_os_numa_node_count_get(void) {
|
||||
if (mi_unlikely(_mi_numa_node_count <= 0)) {
|
||||
long ncount = mi_option_get(mi_option_use_numa_nodes); // given explicitly?
|
||||
if (ncount <= 0) ncount = (long)mi_os_numa_node_countx(); // or detect dynamically
|
||||
_mi_numa_node_count = (size_t)(ncount <= 0 ? 1 : ncount);
|
||||
_mi_verbose_message("using %zd numa regions\n", _mi_numa_node_count);
|
||||
}
|
||||
mi_assert_internal(_mi_numa_node_count >= 1);
|
||||
return _mi_numa_node_count;
|
||||
}
|
||||
|
||||
int _mi_os_numa_node_get(mi_os_tld_t* tld) {
|
||||
UNUSED(tld);
|
||||
size_t numa_count = _mi_os_numa_node_count();
|
||||
if (numa_count<=1) return 0; // optimize on single numa node systems: always node 0
|
||||
// never more than the node count and >= 0
|
||||
size_t numa_node = mi_os_numa_nodex();
|
||||
if (numa_node >= numa_count) { numa_node = numa_node % numa_count; }
|
||||
return (int)numa_node;
|
||||
}
|
||||
|
@ -178,20 +178,20 @@ static bool mi_heap_contains_queue(const mi_heap_t* heap, const mi_page_queue_t*
|
||||
#endif
|
||||
|
||||
static mi_page_queue_t* mi_page_queue_of(const mi_page_t* page) {
|
||||
uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : _mi_bin(page->block_size));
|
||||
mi_heap_t* heap = page->heap;
|
||||
uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : _mi_bin(page->xblock_size));
|
||||
mi_heap_t* heap = mi_page_heap(page);
|
||||
mi_assert_internal(heap != NULL && bin <= MI_BIN_FULL);
|
||||
mi_page_queue_t* pq = &heap->pages[bin];
|
||||
mi_assert_internal(bin >= MI_BIN_HUGE || page->block_size == pq->block_size);
|
||||
mi_assert_internal(bin >= MI_BIN_HUGE || page->xblock_size == pq->block_size);
|
||||
mi_assert_expensive(mi_page_queue_contains(pq, page));
|
||||
return pq;
|
||||
}
|
||||
|
||||
static mi_page_queue_t* mi_heap_page_queue_of(mi_heap_t* heap, const mi_page_t* page) {
|
||||
uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : _mi_bin(page->block_size));
|
||||
uint8_t bin = (mi_page_is_in_full(page) ? MI_BIN_FULL : _mi_bin(page->xblock_size));
|
||||
mi_assert_internal(bin <= MI_BIN_FULL);
|
||||
mi_page_queue_t* pq = &heap->pages[bin];
|
||||
mi_assert_internal(mi_page_is_in_full(page) || page->block_size == pq->block_size);
|
||||
mi_assert_internal(mi_page_is_in_full(page) || page->xblock_size == pq->block_size);
|
||||
return pq;
|
||||
}
|
||||
|
||||
@ -246,35 +246,35 @@ static bool mi_page_queue_is_empty(mi_page_queue_t* queue) {
|
||||
static void mi_page_queue_remove(mi_page_queue_t* queue, mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
mi_assert_expensive(mi_page_queue_contains(queue, page));
|
||||
mi_assert_internal(page->block_size == queue->block_size || (page->block_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(queue)) || (mi_page_is_in_full(page) && mi_page_queue_is_full(queue)));
|
||||
mi_assert_internal(page->xblock_size == queue->block_size || (page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(queue)) || (mi_page_is_in_full(page) && mi_page_queue_is_full(queue)));
|
||||
mi_heap_t* heap = mi_page_heap(page);
|
||||
if (page->prev != NULL) page->prev->next = page->next;
|
||||
if (page->next != NULL) page->next->prev = page->prev;
|
||||
if (page == queue->last) queue->last = page->prev;
|
||||
if (page == queue->first) {
|
||||
queue->first = page->next;
|
||||
// update first
|
||||
mi_heap_t* heap = page->heap;
|
||||
mi_assert_internal(mi_heap_contains_queue(heap, queue));
|
||||
mi_heap_queue_first_update(heap,queue);
|
||||
}
|
||||
page->heap->page_count--;
|
||||
heap->page_count--;
|
||||
page->next = NULL;
|
||||
page->prev = NULL;
|
||||
mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), NULL);
|
||||
// mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), NULL);
|
||||
mi_page_set_in_full(page,false);
|
||||
}
|
||||
|
||||
|
||||
static void mi_page_queue_push(mi_heap_t* heap, mi_page_queue_t* queue, mi_page_t* page) {
|
||||
mi_assert_internal(page->heap == NULL);
|
||||
mi_assert_internal(mi_page_heap(page) == heap);
|
||||
mi_assert_internal(!mi_page_queue_contains(queue, page));
|
||||
mi_assert_internal(_mi_page_segment(page)->page_kind != MI_PAGE_HUGE);
|
||||
mi_assert_internal(page->block_size == queue->block_size ||
|
||||
(page->block_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(queue)) ||
|
||||
mi_assert_internal(page->xblock_size == queue->block_size ||
|
||||
(page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(queue)) ||
|
||||
(mi_page_is_in_full(page) && mi_page_queue_is_full(queue)));
|
||||
|
||||
mi_page_set_in_full(page, mi_page_queue_is_full(queue));
|
||||
mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), heap);
|
||||
// mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), heap);
|
||||
page->next = queue->first;
|
||||
page->prev = NULL;
|
||||
if (queue->first != NULL) {
|
||||
@ -296,19 +296,19 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro
|
||||
mi_assert_internal(page != NULL);
|
||||
mi_assert_expensive(mi_page_queue_contains(from, page));
|
||||
mi_assert_expensive(!mi_page_queue_contains(to, page));
|
||||
mi_assert_internal((page->block_size == to->block_size && page->block_size == from->block_size) ||
|
||||
(page->block_size == to->block_size && mi_page_queue_is_full(from)) ||
|
||||
(page->block_size == from->block_size && mi_page_queue_is_full(to)) ||
|
||||
(page->block_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(to)) ||
|
||||
(page->block_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_full(to)));
|
||||
mi_assert_internal((page->xblock_size == to->block_size && page->xblock_size == from->block_size) ||
|
||||
(page->xblock_size == to->block_size && mi_page_queue_is_full(from)) ||
|
||||
(page->xblock_size == from->block_size && mi_page_queue_is_full(to)) ||
|
||||
(page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_huge(to)) ||
|
||||
(page->xblock_size > MI_LARGE_OBJ_SIZE_MAX && mi_page_queue_is_full(to)));
|
||||
|
||||
mi_heap_t* heap = mi_page_heap(page);
|
||||
if (page->prev != NULL) page->prev->next = page->next;
|
||||
if (page->next != NULL) page->next->prev = page->prev;
|
||||
if (page == from->last) from->last = page->prev;
|
||||
if (page == from->first) {
|
||||
from->first = page->next;
|
||||
// update first
|
||||
mi_heap_t* heap = page->heap;
|
||||
mi_assert_internal(mi_heap_contains_queue(heap, from));
|
||||
mi_heap_queue_first_update(heap, from);
|
||||
}
|
||||
@ -316,14 +316,14 @@ static void mi_page_queue_enqueue_from(mi_page_queue_t* to, mi_page_queue_t* fro
|
||||
page->prev = to->last;
|
||||
page->next = NULL;
|
||||
if (to->last != NULL) {
|
||||
mi_assert_internal(page->heap == to->last->heap);
|
||||
mi_assert_internal(heap == mi_page_heap(to->last));
|
||||
to->last->next = page;
|
||||
to->last = page;
|
||||
}
|
||||
else {
|
||||
to->first = page;
|
||||
to->last = page;
|
||||
mi_heap_queue_first_update(page->heap, to);
|
||||
mi_heap_queue_first_update(heap, to);
|
||||
}
|
||||
|
||||
mi_page_set_in_full(page, mi_page_queue_is_full(to));
|
||||
@ -338,7 +338,7 @@ size_t _mi_page_queue_append(mi_heap_t* heap, mi_page_queue_t* pq, mi_page_queue
|
||||
// set append pages to new heap and count
|
||||
size_t count = 0;
|
||||
for (mi_page_t* page = append->first; page != NULL; page = page->next) {
|
||||
mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), heap);
|
||||
mi_page_set_heap(page,heap);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
351
src/page.c
351
src/page.c
@ -29,16 +29,17 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
----------------------------------------------------------- */
|
||||
|
||||
// Index a block in a page
|
||||
static inline mi_block_t* mi_page_block_at(const mi_page_t* page, void* page_start, size_t i) {
|
||||
static inline mi_block_t* mi_page_block_at(const mi_page_t* page, void* page_start, size_t block_size, size_t i) {
|
||||
UNUSED(page);
|
||||
mi_assert_internal(page != NULL);
|
||||
mi_assert_internal(i <= page->reserved);
|
||||
return (mi_block_t*)((uint8_t*)page_start + (i * page->block_size));
|
||||
return (mi_block_t*)((uint8_t*)page_start + (i * block_size));
|
||||
}
|
||||
|
||||
static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t size, mi_stats_t* stats);
|
||||
static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t size, mi_tld_t* tld);
|
||||
static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_tld_t* tld);
|
||||
|
||||
|
||||
#if (MI_DEBUG>1)
|
||||
#if (MI_DEBUG>=3)
|
||||
static size_t mi_page_list_count(mi_page_t* page, mi_block_t* head) {
|
||||
size_t count = 0;
|
||||
while (head != NULL) {
|
||||
@ -69,13 +70,14 @@ static bool mi_page_list_is_valid(mi_page_t* page, mi_block_t* p) {
|
||||
}
|
||||
|
||||
static bool mi_page_is_valid_init(mi_page_t* page) {
|
||||
mi_assert_internal(page->block_size > 0);
|
||||
mi_assert_internal(page->xblock_size > 0);
|
||||
mi_assert_internal(page->used <= page->capacity);
|
||||
mi_assert_internal(page->capacity <= page->reserved);
|
||||
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
uint8_t* start = _mi_page_start(segment,page,NULL);
|
||||
mi_assert_internal(start == _mi_segment_page_start(segment,page,page->block_size,NULL));
|
||||
mi_assert_internal(start == _mi_segment_page_start(segment,page,bsize,NULL,NULL));
|
||||
//mi_assert_internal(start + page->capacity*page->block_size == page->top);
|
||||
|
||||
mi_assert_internal(mi_page_list_is_valid(page,page->free));
|
||||
@ -89,10 +91,10 @@ static bool mi_page_is_valid_init(mi_page_t* page) {
|
||||
}
|
||||
#endif
|
||||
|
||||
mi_block_t* tfree = mi_tf_block(page->thread_free);
|
||||
mi_block_t* tfree = mi_page_thread_free(page);
|
||||
mi_assert_internal(mi_page_list_is_valid(page, tfree));
|
||||
size_t tfree_count = mi_page_list_count(page, tfree);
|
||||
mi_assert_internal(tfree_count <= page->thread_freed + 1);
|
||||
//size_t tfree_count = mi_page_list_count(page, tfree);
|
||||
//mi_assert_internal(tfree_count <= page->thread_freed + 1);
|
||||
|
||||
size_t free_count = mi_page_list_count(page, page->free) + mi_page_list_count(page, page->local_free);
|
||||
mi_assert_internal(page->used + free_count == page->capacity);
|
||||
@ -103,42 +105,44 @@ static bool mi_page_is_valid_init(mi_page_t* page) {
|
||||
bool _mi_page_is_valid(mi_page_t* page) {
|
||||
mi_assert_internal(mi_page_is_valid_init(page));
|
||||
#if MI_SECURE
|
||||
mi_assert_internal(page->cookie != 0);
|
||||
mi_assert_internal(page->key != 0);
|
||||
#endif
|
||||
if (page->heap!=NULL) {
|
||||
if (mi_page_heap(page)!=NULL) {
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
mi_assert_internal(!_mi_process_is_initialized || segment->thread_id == page->heap->thread_id || segment->thread_id==0);
|
||||
mi_assert_internal(!_mi_process_is_initialized || segment->thread_id == mi_page_heap(page)->thread_id || segment->thread_id==0);
|
||||
if (segment->page_kind != MI_PAGE_HUGE) {
|
||||
mi_page_queue_t* pq = mi_page_queue_of(page);
|
||||
mi_assert_internal(mi_page_queue_contains(pq, page));
|
||||
mi_assert_internal(pq->block_size==page->block_size || page->block_size > MI_LARGE_OBJ_SIZE_MAX || mi_page_is_in_full(page));
|
||||
mi_assert_internal(mi_heap_contains_queue(page->heap,pq));
|
||||
mi_assert_internal(pq->block_size==mi_page_block_size(page) || mi_page_block_size(page) > MI_LARGE_OBJ_SIZE_MAX || mi_page_is_in_full(page));
|
||||
mi_assert_internal(mi_heap_contains_queue(mi_page_heap(page),pq));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay ) {
|
||||
void _mi_page_use_delayed_free(mi_page_t* page, mi_delayed_t delay, bool override_never) {
|
||||
mi_thread_free_t tfree;
|
||||
mi_thread_free_t tfreex;
|
||||
|
||||
mi_delayed_t old_delay;
|
||||
do {
|
||||
tfreex = tfree = page->thread_free;
|
||||
if (mi_unlikely(mi_tf_delayed(tfree) < MI_DELAYED_FREEING)) {
|
||||
tfreex = mi_tf_set_delayed(tfree,delay);
|
||||
}
|
||||
else if (mi_unlikely(mi_tf_delayed(tfree) == MI_DELAYED_FREEING)) {
|
||||
tfree = mi_atomic_read(&page->xthread_free); // note: must acquire as we can break this loop and not do a CAS
|
||||
tfreex = mi_tf_set_delayed(tfree, delay);
|
||||
old_delay = mi_tf_delayed(tfree);
|
||||
if (mi_unlikely(old_delay == MI_DELAYED_FREEING)) {
|
||||
mi_atomic_yield(); // delay until outstanding MI_DELAYED_FREEING are done.
|
||||
continue; // and try again
|
||||
// tfree = mi_tf_set_delayed(tfree, MI_NO_DELAYED_FREE); // will cause CAS to busy fail
|
||||
}
|
||||
}
|
||||
while((mi_tf_delayed(tfreex) != mi_tf_delayed(tfree)) && // avoid atomic operation if already equal
|
||||
!mi_atomic_cas_weak(mi_atomic_cast(uintptr_t,&page->thread_free), tfreex, tfree));
|
||||
else if (delay == old_delay) {
|
||||
break; // avoid atomic operation if already equal
|
||||
}
|
||||
else if (!override_never && old_delay == MI_NEVER_DELAYED_FREE) {
|
||||
break; // leave never-delayed flag set
|
||||
}
|
||||
} while ((old_delay == MI_DELAYED_FREEING) ||
|
||||
!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree));
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Page collect the `local_free` and `thread_free` lists
|
||||
----------------------------------------------------------- */
|
||||
@ -153,17 +157,17 @@ static void _mi_page_thread_free_collect(mi_page_t* page)
|
||||
mi_thread_free_t tfree;
|
||||
mi_thread_free_t tfreex;
|
||||
do {
|
||||
tfree = page->thread_free;
|
||||
tfree = mi_atomic_read_relaxed(&page->xthread_free);
|
||||
head = mi_tf_block(tfree);
|
||||
tfreex = mi_tf_set_block(tfree,NULL);
|
||||
} while (!mi_atomic_cas_weak(mi_atomic_cast(uintptr_t,&page->thread_free), tfreex, tfree));
|
||||
} while (!mi_atomic_cas_weak(&page->xthread_free, tfreex, tfree));
|
||||
|
||||
// return if the list is empty
|
||||
if (head == NULL) return;
|
||||
|
||||
// find the tail -- also to get a proper count (without data races)
|
||||
uintptr_t max_count = page->capacity; // cannot collect more than capacity
|
||||
uintptr_t count = 1;
|
||||
uint32_t max_count = page->capacity; // cannot collect more than capacity
|
||||
uint32_t count = 1;
|
||||
mi_block_t* tail = head;
|
||||
mi_block_t* next;
|
||||
while ((next = mi_block_next(page,tail)) != NULL && count <= max_count) {
|
||||
@ -172,7 +176,7 @@ static void _mi_page_thread_free_collect(mi_page_t* page)
|
||||
}
|
||||
// if `count > max_count` there was a memory corruption (possibly infinite list due to double multi-threaded free)
|
||||
if (count > max_count) {
|
||||
_mi_fatal_error("corrupted thread-free list\n");
|
||||
_mi_error_message(EFAULT, "corrupted thread-free list\n");
|
||||
return; // the thread-free items cannot be freed
|
||||
}
|
||||
|
||||
@ -181,7 +185,6 @@ static void _mi_page_thread_free_collect(mi_page_t* page)
|
||||
page->local_free = head;
|
||||
|
||||
// update counts now
|
||||
mi_atomic_subu(&page->thread_freed, count);
|
||||
page->used -= count;
|
||||
}
|
||||
|
||||
@ -189,7 +192,7 @@ void _mi_page_free_collect(mi_page_t* page, bool force) {
|
||||
mi_assert_internal(page!=NULL);
|
||||
|
||||
// collect the thread free list
|
||||
if (force || mi_tf_block(page->thread_free) != NULL) { // quick test to avoid an atomic operation
|
||||
if (force || mi_page_thread_free(page) != NULL) { // quick test to avoid an atomic operation
|
||||
_mi_page_thread_free_collect(page);
|
||||
}
|
||||
|
||||
@ -227,10 +230,12 @@ void _mi_page_free_collect(mi_page_t* page, bool force) {
|
||||
// called from segments when reclaiming abandoned pages
|
||||
void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page) {
|
||||
mi_assert_expensive(mi_page_is_valid_init(page));
|
||||
mi_assert_internal(page->heap == NULL);
|
||||
mi_assert_internal(mi_page_heap(page) == heap);
|
||||
mi_assert_internal(mi_page_thread_free_flag(page) != MI_NEVER_DELAYED_FREE);
|
||||
mi_assert_internal(_mi_page_segment(page)->page_kind != MI_PAGE_HUGE);
|
||||
_mi_page_free_collect(page,false);
|
||||
mi_page_queue_t* pq = mi_page_queue(heap, page->block_size);
|
||||
mi_assert_internal(!page->is_reset);
|
||||
// TODO: push on full queue immediately if it is full?
|
||||
mi_page_queue_t* pq = mi_page_queue(heap, mi_page_block_size(page));
|
||||
mi_page_queue_push(heap, pq, page);
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
}
|
||||
@ -238,11 +243,16 @@ void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page) {
|
||||
// allocate a fresh page from a segment
|
||||
static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size_t block_size) {
|
||||
mi_assert_internal(pq==NULL||mi_heap_contains_queue(heap, pq));
|
||||
mi_page_t* page = _mi_segment_page_alloc(block_size, &heap->tld->segments, &heap->tld->os);
|
||||
if (page == NULL) return NULL;
|
||||
mi_assert_internal(pq==NULL||block_size == pq->block_size);
|
||||
mi_page_t* page = _mi_segment_page_alloc(heap, block_size, &heap->tld->segments, &heap->tld->os);
|
||||
if (page == NULL) {
|
||||
// this may be out-of-memory, or an abandoned page was reclaimed (and in our queue)
|
||||
return NULL;
|
||||
}
|
||||
// a fresh page was found, initialize it
|
||||
mi_assert_internal(pq==NULL || _mi_page_segment(page)->page_kind != MI_PAGE_HUGE);
|
||||
mi_page_init(heap, page, block_size, &heap->tld->stats);
|
||||
_mi_stat_increase( &heap->tld->stats.pages, 1);
|
||||
mi_page_init(heap, page, block_size, heap->tld);
|
||||
_mi_stat_increase(&heap->tld->stats.pages, 1);
|
||||
if (pq!=NULL) mi_page_queue_push(heap, pq, page); // huge pages use pq==NULL
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
return page;
|
||||
@ -251,22 +261,10 @@ static mi_page_t* mi_page_fresh_alloc(mi_heap_t* heap, mi_page_queue_t* pq, size
|
||||
// Get a fresh page to use
|
||||
static mi_page_t* mi_page_fresh(mi_heap_t* heap, mi_page_queue_t* pq) {
|
||||
mi_assert_internal(mi_heap_contains_queue(heap, pq));
|
||||
|
||||
// try to reclaim an abandoned page first
|
||||
mi_page_t* page = pq->first;
|
||||
if (!heap->no_reclaim &&
|
||||
_mi_segment_try_reclaim_abandoned(heap, false, &heap->tld->segments) &&
|
||||
page != pq->first)
|
||||
{
|
||||
// we reclaimed, and we got lucky with a reclaimed page in our queue
|
||||
page = pq->first;
|
||||
if (page->free != NULL) return page;
|
||||
}
|
||||
// otherwise allocate the page
|
||||
page = mi_page_fresh_alloc(heap, pq, pq->block_size);
|
||||
mi_page_t* page = mi_page_fresh_alloc(heap, pq, pq->block_size);
|
||||
if (page==NULL) return NULL;
|
||||
mi_assert_internal(pq->block_size==page->block_size);
|
||||
mi_assert_internal(pq==mi_page_queue(heap,page->block_size));
|
||||
mi_assert_internal(pq->block_size==mi_page_block_size(page));
|
||||
mi_assert_internal(pq==mi_page_queue(heap, mi_page_block_size(page)));
|
||||
return page;
|
||||
}
|
||||
|
||||
@ -275,25 +273,24 @@ static mi_page_t* mi_page_fresh(mi_heap_t* heap, mi_page_queue_t* pq) {
|
||||
(put there by other threads if they deallocated in a full page)
|
||||
----------------------------------------------------------- */
|
||||
void _mi_heap_delayed_free(mi_heap_t* heap) {
|
||||
// take over the list
|
||||
// take over the list (note: no atomic exchange is it is often NULL)
|
||||
mi_block_t* block;
|
||||
do {
|
||||
block = (mi_block_t*)heap->thread_delayed_free;
|
||||
} while (block != NULL && !mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), NULL, block));
|
||||
block = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free);
|
||||
} while (block != NULL && !mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, NULL, block));
|
||||
|
||||
// and free them all
|
||||
while(block != NULL) {
|
||||
mi_block_t* next = mi_block_nextx(heap,block, heap->cookie);
|
||||
mi_block_t* next = mi_block_nextx(heap,block, heap->key[0], heap->key[1]);
|
||||
// use internal free instead of regular one to keep stats etc correct
|
||||
if (!_mi_free_delayed_block(block)) {
|
||||
// we might already start delayed freeing while another thread has not yet
|
||||
// reset the delayed_freeing flag; in that case delay it further by reinserting.
|
||||
mi_block_t* dfree;
|
||||
do {
|
||||
dfree = (mi_block_t*)heap->thread_delayed_free;
|
||||
mi_block_set_nextx(heap, block, dfree, heap->cookie);
|
||||
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
||||
|
||||
dfree = mi_atomic_read_ptr_relaxed(mi_block_t,&heap->thread_delayed_free);
|
||||
mi_block_set_nextx(heap, block, dfree, heap->key[0], heap->key[1]);
|
||||
} while (!mi_atomic_cas_ptr_weak(mi_block_t,&heap->thread_delayed_free, block, dfree));
|
||||
}
|
||||
block = next;
|
||||
}
|
||||
@ -308,11 +305,9 @@ void _mi_page_unfull(mi_page_t* page) {
|
||||
mi_assert_internal(page != NULL);
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
mi_assert_internal(mi_page_is_in_full(page));
|
||||
|
||||
_mi_page_use_delayed_free(page, MI_NO_DELAYED_FREE);
|
||||
if (!mi_page_is_in_full(page)) return;
|
||||
|
||||
mi_heap_t* heap = page->heap;
|
||||
mi_heap_t* heap = mi_page_heap(page);
|
||||
mi_page_queue_t* pqfull = &heap->pages[MI_BIN_FULL];
|
||||
mi_page_set_in_full(page, false); // to get the right queue
|
||||
mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page);
|
||||
@ -325,10 +320,8 @@ static void mi_page_to_full(mi_page_t* page, mi_page_queue_t* pq) {
|
||||
mi_assert_internal(!mi_page_immediate_available(page));
|
||||
mi_assert_internal(!mi_page_is_in_full(page));
|
||||
|
||||
_mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE);
|
||||
if (mi_page_is_in_full(page)) return;
|
||||
|
||||
mi_page_queue_enqueue_from(&page->heap->pages[MI_BIN_FULL], pq, page);
|
||||
mi_page_queue_enqueue_from(&mi_page_heap(page)->pages[MI_BIN_FULL], pq, page);
|
||||
_mi_page_free_collect(page,false); // try to collect right away in case another thread freed just before MI_USE_DELAYED_FREE was set
|
||||
}
|
||||
|
||||
@ -341,28 +334,27 @@ void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) {
|
||||
mi_assert_internal(page != NULL);
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
mi_assert_internal(pq == mi_page_queue_of(page));
|
||||
mi_assert_internal(page->heap != NULL);
|
||||
mi_assert_internal(mi_page_heap(page) != NULL);
|
||||
|
||||
#if MI_DEBUG > 1
|
||||
mi_heap_t* pheap = (mi_heap_t*)mi_atomic_read_ptr(mi_atomic_cast(void*, &page->heap));
|
||||
#endif
|
||||
mi_heap_t* pheap = mi_page_heap(page);
|
||||
|
||||
// remove from our page list
|
||||
mi_segments_tld_t* segments_tld = &page->heap->tld->segments;
|
||||
mi_segments_tld_t* segments_tld = &pheap->tld->segments;
|
||||
mi_page_queue_remove(pq, page);
|
||||
|
||||
// page is no longer associated with our heap
|
||||
mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), NULL);
|
||||
mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE);
|
||||
mi_page_set_heap(page, NULL);
|
||||
|
||||
#if MI_DEBUG>1
|
||||
// check there are no references left..
|
||||
for (mi_block_t* block = (mi_block_t*)pheap->thread_delayed_free; block != NULL; block = mi_block_nextx(pheap, block, pheap->cookie)) {
|
||||
for (mi_block_t* block = (mi_block_t*)pheap->thread_delayed_free; block != NULL; block = mi_block_nextx(pheap, block, pheap->key[0], pheap->key[1])) {
|
||||
mi_assert_internal(_mi_ptr_page(block) != page);
|
||||
}
|
||||
#endif
|
||||
|
||||
// and abandon it
|
||||
mi_assert_internal(page->heap == NULL);
|
||||
mi_assert_internal(mi_page_heap(page) == NULL);
|
||||
_mi_segment_page_abandon(page,segments_tld);
|
||||
}
|
||||
|
||||
@ -373,36 +365,23 @@ void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) {
|
||||
mi_assert_expensive(_mi_page_is_valid(page));
|
||||
mi_assert_internal(pq == mi_page_queue_of(page));
|
||||
mi_assert_internal(mi_page_all_free(page));
|
||||
#if MI_DEBUG>1
|
||||
// check if we can safely free
|
||||
mi_thread_free_t free = mi_tf_set_delayed(page->thread_free,MI_NEVER_DELAYED_FREE);
|
||||
free = mi_atomic_exchange(&page->thread_free, free);
|
||||
mi_assert_internal(mi_tf_delayed(free) != MI_DELAYED_FREEING);
|
||||
#endif
|
||||
mi_assert_internal(mi_page_thread_free_flag(page)!=MI_DELAYED_FREEING);
|
||||
|
||||
// no more aligned blocks in here
|
||||
mi_page_set_has_aligned(page, false);
|
||||
|
||||
// account for huge pages here
|
||||
// (note: no longer necessary as huge pages are always abandoned)
|
||||
if (page->block_size > MI_LARGE_OBJ_SIZE_MAX) {
|
||||
if (page->block_size > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_decrease(&page->heap->tld->stats.giant, page->block_size);
|
||||
}
|
||||
else {
|
||||
_mi_stat_decrease(&page->heap->tld->stats.huge, page->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
// remove from the page list
|
||||
// (no need to do _mi_heap_delayed_free first as all blocks are already free)
|
||||
mi_segments_tld_t* segments_tld = &page->heap->tld->segments;
|
||||
mi_segments_tld_t* segments_tld = &mi_page_heap(page)->tld->segments;
|
||||
mi_page_queue_remove(pq, page);
|
||||
|
||||
// and free it
|
||||
mi_assert_internal(page->heap == NULL);
|
||||
mi_page_set_heap(page,NULL);
|
||||
_mi_segment_page_free(page, force, segments_tld);
|
||||
}
|
||||
|
||||
#define MI_MAX_RETIRE_SIZE (4*MI_SMALL_SIZE_MAX)
|
||||
|
||||
// Retire a page with no more used blocks
|
||||
// Important to not retire too quickly though as new
|
||||
// allocations might coming.
|
||||
@ -420,20 +399,40 @@ void _mi_page_retire(mi_page_t* page) {
|
||||
// (or we end up retiring and re-allocating most of the time)
|
||||
// NOTE: refine this more: we should not retire if this
|
||||
// is the only page left with free blocks. It is not clear
|
||||
// how to check this efficiently though...
|
||||
// how to check this efficiently though...
|
||||
// for now, we don't retire if it is the only page left of this size class.
|
||||
mi_page_queue_t* pq = mi_page_queue_of(page);
|
||||
if (mi_likely(page->block_size <= (MI_SMALL_SIZE_MAX/4))) {
|
||||
// if (mi_page_mostly_used(page->prev) && mi_page_mostly_used(page->next)) {
|
||||
if (pq->last==page && pq->first==page) {
|
||||
if (mi_likely(page->xblock_size <= MI_MAX_RETIRE_SIZE && !mi_page_is_in_full(page))) {
|
||||
if (pq->last==page && pq->first==page) { // the only page in the queue?
|
||||
mi_stat_counter_increase(_mi_stats_main.page_no_retire,1);
|
||||
return; // dont't retire after all
|
||||
page->retire_expire = 16;
|
||||
mi_assert_internal(mi_page_all_free(page));
|
||||
return; // dont't free after all
|
||||
}
|
||||
}
|
||||
|
||||
_mi_page_free(page, pq, false);
|
||||
}
|
||||
|
||||
// free retired pages: we don't need to look at the entire queues
|
||||
// since we only retire pages that are the last one in a queue.
|
||||
void _mi_heap_collect_retired(mi_heap_t* heap, bool force) {
|
||||
for(mi_page_queue_t* pq = heap->pages; pq->block_size <= MI_MAX_RETIRE_SIZE; pq++) {
|
||||
mi_page_t* page = pq->first;
|
||||
if (page != NULL && page->retire_expire != 0) {
|
||||
if (mi_page_all_free(page)) {
|
||||
page->retire_expire--;
|
||||
if (force || page->retire_expire == 0) {
|
||||
_mi_page_free(pq->first, pq, force);
|
||||
}
|
||||
}
|
||||
else {
|
||||
page->retire_expire = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Initialize the initial free list in a page.
|
||||
@ -445,15 +444,15 @@ void _mi_page_retire(mi_page_t* page) {
|
||||
#define MI_MAX_SLICES (1UL << MI_MAX_SLICE_SHIFT)
|
||||
#define MI_MIN_SLICES (2)
|
||||
|
||||
static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* const page, const size_t extend, mi_stats_t* const stats) {
|
||||
static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* const page, const size_t bsize, const size_t extend, mi_stats_t* const stats) {
|
||||
UNUSED(stats);
|
||||
#if (MI_SECURE<=2)
|
||||
mi_assert_internal(page->free == NULL);
|
||||
mi_assert_internal(page->local_free == NULL);
|
||||
#endif
|
||||
mi_assert_internal(page->capacity + extend <= page->reserved);
|
||||
mi_assert_internal(bsize == mi_page_block_size(page));
|
||||
void* const page_area = _mi_page_start(_mi_page_segment(page), page, NULL);
|
||||
const size_t bsize = page->block_size;
|
||||
|
||||
// initialize a randomized free list
|
||||
// set up `slice_count` slices to alternate between
|
||||
@ -467,18 +466,19 @@ static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* co
|
||||
mi_block_t* blocks[MI_MAX_SLICES]; // current start of the slice
|
||||
size_t counts[MI_MAX_SLICES]; // available objects in the slice
|
||||
for (size_t i = 0; i < slice_count; i++) {
|
||||
blocks[i] = mi_page_block_at(page, page_area, page->capacity + i*slice_extend);
|
||||
blocks[i] = mi_page_block_at(page, page_area, bsize, page->capacity + i*slice_extend);
|
||||
counts[i] = slice_extend;
|
||||
}
|
||||
counts[slice_count-1] += (extend % slice_count); // final slice holds the modulus too (todo: distribute evenly?)
|
||||
|
||||
// and initialize the free list by randomly threading through them
|
||||
// set up first element
|
||||
size_t current = _mi_heap_random(heap) % slice_count;
|
||||
const uintptr_t r = _mi_heap_random_next(heap);
|
||||
size_t current = r % slice_count;
|
||||
counts[current]--;
|
||||
mi_block_t* const free_start = blocks[current];
|
||||
// and iterate through the rest
|
||||
uintptr_t rnd = heap->random;
|
||||
// and iterate through the rest; use `random_shuffle` for performance
|
||||
uintptr_t rnd = _mi_random_shuffle(r|1); // ensure not 0
|
||||
for (size_t i = 1; i < extend; i++) {
|
||||
// call random_shuffle only every INTPTR_SIZE rounds
|
||||
const size_t round = i%MI_INTPTR_SIZE;
|
||||
@ -499,10 +499,9 @@ static void mi_page_free_list_extend_secure(mi_heap_t* const heap, mi_page_t* co
|
||||
// prepend to the free list (usually NULL)
|
||||
mi_block_set_next(page, blocks[current], page->free); // end of the list
|
||||
page->free = free_start;
|
||||
heap->random = _mi_random_shuffle(rnd);
|
||||
}
|
||||
|
||||
static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, const size_t extend, mi_stats_t* const stats)
|
||||
static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, const size_t bsize, const size_t extend, mi_stats_t* const stats)
|
||||
{
|
||||
UNUSED(stats);
|
||||
#if (MI_SECURE <= 2)
|
||||
@ -510,18 +509,19 @@ static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, co
|
||||
mi_assert_internal(page->local_free == NULL);
|
||||
#endif
|
||||
mi_assert_internal(page->capacity + extend <= page->reserved);
|
||||
mi_assert_internal(bsize == mi_page_block_size(page));
|
||||
void* const page_area = _mi_page_start(_mi_page_segment(page), page, NULL );
|
||||
const size_t bsize = page->block_size;
|
||||
mi_block_t* const start = mi_page_block_at(page, page_area, page->capacity);
|
||||
|
||||
|
||||
mi_block_t* const start = mi_page_block_at(page, page_area, bsize, page->capacity);
|
||||
|
||||
// initialize a sequential free list
|
||||
mi_block_t* const last = mi_page_block_at(page, page_area, page->capacity + extend - 1);
|
||||
mi_block_t* const last = mi_page_block_at(page, page_area, bsize, 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;
|
||||
}
|
||||
}
|
||||
// prepend to free list (usually `NULL`)
|
||||
mi_block_set_next(page, last, page->free);
|
||||
page->free = start;
|
||||
@ -543,8 +543,7 @@ static mi_decl_noinline void mi_page_free_list_extend( mi_page_t* const page, co
|
||||
// Note: we also experimented with "bump" allocation on the first
|
||||
// allocations but this did not speed up any benchmark (due to an
|
||||
// extra test in malloc? or cache effects?)
|
||||
static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* stats) {
|
||||
UNUSED(stats);
|
||||
static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_tld_t* tld) {
|
||||
mi_assert_expensive(mi_page_is_valid_init(page));
|
||||
#if (MI_SECURE<=2)
|
||||
mi_assert(page->free == NULL);
|
||||
@ -554,12 +553,13 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st
|
||||
if (page->capacity >= page->reserved) return;
|
||||
|
||||
size_t page_size;
|
||||
_mi_page_start(_mi_page_segment(page), page, &page_size);
|
||||
mi_stat_counter_increase(stats->pages_extended, 1);
|
||||
uint8_t* page_start = _mi_page_start(_mi_page_segment(page), page, &page_size);
|
||||
mi_stat_counter_increase(tld->stats.pages_extended, 1);
|
||||
|
||||
// calculate the extend count
|
||||
const size_t bsize = (page->xblock_size < MI_HUGE_BLOCK_SIZE ? page->xblock_size : page_size);
|
||||
size_t extend = page->reserved - page->capacity;
|
||||
size_t max_extend = (page->block_size >= MI_MAX_EXTEND_SIZE ? MI_MIN_EXTEND : MI_MAX_EXTEND_SIZE/(uint32_t)page->block_size);
|
||||
size_t max_extend = (bsize >= MI_MAX_EXTEND_SIZE ? MI_MIN_EXTEND : MI_MAX_EXTEND_SIZE/(uint32_t)bsize);
|
||||
if (max_extend < MI_MIN_EXTEND) max_extend = MI_MIN_EXTEND;
|
||||
|
||||
if (extend > max_extend) {
|
||||
@ -571,16 +571,22 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st
|
||||
mi_assert_internal(extend > 0 && extend + page->capacity <= page->reserved);
|
||||
mi_assert_internal(extend < (1UL<<16));
|
||||
|
||||
// commit on-demand for large and huge pages?
|
||||
if (_mi_page_segment(page)->page_kind >= MI_PAGE_LARGE && !mi_option_is_enabled(mi_option_eager_page_commit)) {
|
||||
uint8_t* start = page_start + (page->capacity * bsize);
|
||||
_mi_mem_commit(start, extend * bsize, NULL, &tld->os);
|
||||
}
|
||||
|
||||
// and append the extend the free list
|
||||
if (extend < MI_MIN_SLICES || MI_SECURE==0) { //!mi_option_is_enabled(mi_option_secure)) {
|
||||
mi_page_free_list_extend(page, extend, stats );
|
||||
mi_page_free_list_extend(page, bsize, extend, &tld->stats );
|
||||
}
|
||||
else {
|
||||
mi_page_free_list_extend_secure(heap, page, extend, stats);
|
||||
mi_page_free_list_extend_secure(heap, page, bsize, extend, &tld->stats);
|
||||
}
|
||||
// enable the new free list
|
||||
page->capacity += (uint16_t)extend;
|
||||
mi_stat_increase(stats->page_committed, extend * page->block_size);
|
||||
mi_stat_increase(tld->stats.page_committed, extend * bsize);
|
||||
|
||||
// extension into zero initialized memory preserves the zero'd free list
|
||||
if (!page->is_zero_init) {
|
||||
@ -590,37 +596,40 @@ static void mi_page_extend_free(mi_heap_t* heap, mi_page_t* page, mi_stats_t* st
|
||||
}
|
||||
|
||||
// Initialize a fresh page
|
||||
static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi_stats_t* stats) {
|
||||
static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi_tld_t* tld) {
|
||||
mi_assert(page != NULL);
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
mi_assert(segment != NULL);
|
||||
mi_assert_internal(block_size > 0);
|
||||
// set fields
|
||||
mi_page_set_heap(page, heap);
|
||||
size_t page_size;
|
||||
_mi_segment_page_start(segment, page, block_size, &page_size);
|
||||
page->block_size = block_size;
|
||||
_mi_segment_page_start(segment, page, block_size, &page_size, NULL);
|
||||
page->xblock_size = (block_size < MI_HUGE_BLOCK_SIZE ? (uint32_t)block_size : MI_HUGE_BLOCK_SIZE);
|
||||
mi_assert_internal(page_size / block_size < (1L<<16));
|
||||
page->reserved = (uint16_t)(page_size / block_size);
|
||||
#ifdef MI_ENCODE_FREELIST
|
||||
page->cookie = _mi_heap_random(heap) | 1;
|
||||
page->key[0] = _mi_heap_random_next(heap);
|
||||
page->key[1] = _mi_heap_random_next(heap);
|
||||
#endif
|
||||
page->is_zero = page->is_zero_init;
|
||||
|
||||
mi_assert_internal(page->capacity == 0);
|
||||
mi_assert_internal(page->free == NULL);
|
||||
mi_assert_internal(page->used == 0);
|
||||
mi_assert_internal(page->thread_free == 0);
|
||||
mi_assert_internal(page->thread_freed == 0);
|
||||
mi_assert_internal(page->xthread_free == 0);
|
||||
mi_assert_internal(page->next == NULL);
|
||||
mi_assert_internal(page->prev == NULL);
|
||||
mi_assert_internal(page->retire_expire == 0);
|
||||
mi_assert_internal(!mi_page_has_aligned(page));
|
||||
#if (MI_ENCODE_FREELIST)
|
||||
mi_assert_internal(page->cookie != 0);
|
||||
mi_assert_internal(page->key[0] != 0);
|
||||
mi_assert_internal(page->key[1] != 0);
|
||||
#endif
|
||||
mi_assert_expensive(mi_page_is_valid_init(page));
|
||||
|
||||
// initialize an initial free list
|
||||
mi_page_extend_free(heap,page,stats);
|
||||
mi_page_extend_free(heap,page,tld);
|
||||
mi_assert(mi_page_immediate_available(page));
|
||||
}
|
||||
|
||||
@ -630,42 +639,27 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi
|
||||
-------------------------------------------------------------*/
|
||||
|
||||
// Find a page with free blocks of `page->block_size`.
|
||||
static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq)
|
||||
static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* pq, bool first_try)
|
||||
{
|
||||
// search through the pages in "next fit" order
|
||||
mi_page_t* rpage = NULL;
|
||||
size_t count = 0;
|
||||
size_t page_free_count = 0;
|
||||
mi_page_t* page = pq->first;
|
||||
while( page != NULL)
|
||||
while (page != NULL)
|
||||
{
|
||||
mi_page_t* next = page->next; // remember next
|
||||
count++;
|
||||
|
||||
// 0. collect freed blocks by us and other threads
|
||||
_mi_page_free_collect(page,false);
|
||||
_mi_page_free_collect(page, false);
|
||||
|
||||
// 1. if the page contains free blocks, we are done
|
||||
if (mi_page_immediate_available(page)) {
|
||||
// If all blocks are free, we might retire this page instead.
|
||||
// do this at most 8 times to bound allocation time.
|
||||
// (note: this can happen if a page was earlier not retired due
|
||||
// to having neighbours that were mostly full or due to concurrent frees)
|
||||
if (page_free_count < 8 && mi_page_all_free(page)) {
|
||||
page_free_count++;
|
||||
if (rpage != NULL) _mi_page_free(rpage,pq,false);
|
||||
rpage = page;
|
||||
page = next;
|
||||
continue; // and keep looking
|
||||
}
|
||||
else {
|
||||
break; // pick this one
|
||||
}
|
||||
break; // pick this one
|
||||
}
|
||||
|
||||
// 2. Try to extend
|
||||
if (page->capacity < page->reserved) {
|
||||
mi_page_extend_free(heap, page, &heap->tld->stats);
|
||||
mi_page_extend_free(heap, page, heap->tld);
|
||||
mi_assert_internal(mi_page_immediate_available(page));
|
||||
break;
|
||||
}
|
||||
@ -673,50 +667,50 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p
|
||||
// 3. If the page is completely full, move it to the `mi_pages_full`
|
||||
// queue so we don't visit long-lived pages too often.
|
||||
mi_assert_internal(!mi_page_is_in_full(page) && !mi_page_immediate_available(page));
|
||||
mi_page_to_full(page,pq);
|
||||
mi_page_to_full(page, pq);
|
||||
|
||||
page = next;
|
||||
} // for each page
|
||||
|
||||
mi_stat_counter_increase(heap->tld->stats.searches,count);
|
||||
|
||||
if (page == NULL) {
|
||||
page = rpage;
|
||||
rpage = NULL;
|
||||
}
|
||||
if (rpage != NULL) {
|
||||
_mi_page_free(rpage,pq,false);
|
||||
}
|
||||
mi_stat_counter_increase(heap->tld->stats.searches, count);
|
||||
|
||||
if (page == NULL) {
|
||||
_mi_heap_collect_retired(heap, false); // perhaps make a page available
|
||||
page = mi_page_fresh(heap, pq);
|
||||
if (page == NULL && first_try) {
|
||||
// out-of-memory _or_ an abandoned page with free blocks was reclaimed, try once again
|
||||
page = mi_page_queue_find_free_ex(heap, pq, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mi_assert(pq->first == page);
|
||||
page->retire_expire = 0;
|
||||
}
|
||||
mi_assert_internal(page == NULL || mi_page_immediate_available(page));
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Find a page with free blocks of `size`.
|
||||
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_SECURE >= 3) && page->capacity < page->reserved && ((_mi_heap_random(heap) & 1) == 1)) {
|
||||
if ((MI_SECURE >= 3) && page->capacity < page->reserved && ((_mi_heap_random_next(heap) & 1) == 1)) {
|
||||
// in secure mode, we extend half the time to increase randomness
|
||||
mi_page_extend_free(heap, page, &heap->tld->stats);
|
||||
mi_page_extend_free(heap, page, heap->tld);
|
||||
mi_assert_internal(mi_page_immediate_available(page));
|
||||
}
|
||||
else {
|
||||
_mi_page_free_collect(page,false);
|
||||
}
|
||||
if (mi_page_immediate_available(page)) {
|
||||
page->retire_expire = 0;
|
||||
return page; // fast path
|
||||
}
|
||||
}
|
||||
return mi_page_queue_find_free_ex(heap, pq);
|
||||
return mi_page_queue_find_free_ex(heap, pq, true);
|
||||
}
|
||||
|
||||
|
||||
@ -728,18 +722,20 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) {
|
||||
----------------------------------------------------------- */
|
||||
|
||||
static mi_deferred_free_fun* volatile deferred_free = NULL;
|
||||
static volatile _Atomic(void*) deferred_arg; // = NULL
|
||||
|
||||
void _mi_deferred_free(mi_heap_t* heap, bool force) {
|
||||
heap->tld->heartbeat++;
|
||||
if (deferred_free != NULL && !heap->tld->recurse) {
|
||||
heap->tld->recurse = true;
|
||||
deferred_free(force, heap->tld->heartbeat);
|
||||
deferred_free(force, heap->tld->heartbeat, mi_atomic_read_ptr_relaxed(void,&deferred_arg));
|
||||
heap->tld->recurse = false;
|
||||
}
|
||||
}
|
||||
|
||||
void mi_register_deferred_free(mi_deferred_free_fun* fn) mi_attr_noexcept {
|
||||
void mi_register_deferred_free(mi_deferred_free_fun* fn, void* arg) mi_attr_noexcept {
|
||||
deferred_free = fn;
|
||||
mi_atomic_write_ptr(void,&deferred_arg, arg);
|
||||
}
|
||||
|
||||
|
||||
@ -753,17 +749,18 @@ void mi_register_deferred_free(mi_deferred_free_fun* fn) mi_attr_noexcept {
|
||||
// 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_os_good_alloc_size(size);
|
||||
mi_assert_internal(_mi_bin(block_size) == MI_BIN_HUGE);
|
||||
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) {
|
||||
const size_t bsize = mi_page_block_size(page);
|
||||
mi_assert_internal(mi_page_immediate_available(page));
|
||||
mi_assert_internal(page->block_size == block_size);
|
||||
mi_assert_internal(bsize >= size);
|
||||
mi_assert_internal(_mi_page_segment(page)->page_kind==MI_PAGE_HUGE);
|
||||
mi_assert_internal(_mi_page_segment(page)->used==1);
|
||||
mi_assert_internal(_mi_page_segment(page)->thread_id==0); // abandoned, not in the huge queue
|
||||
mi_atomic_write_ptr(mi_atomic_cast(void*, &page->heap), NULL);
|
||||
mi_page_set_heap(page, NULL);
|
||||
|
||||
if (page->block_size > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
if (bsize > MI_HUGE_OBJ_SIZE_MAX) {
|
||||
_mi_stat_increase(&heap->tld->stats.giant, block_size);
|
||||
_mi_stat_counter_increase(&heap->tld->stats.giant_count, 1);
|
||||
}
|
||||
@ -771,7 +768,7 @@ static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size) {
|
||||
_mi_stat_increase(&heap->tld->stats.huge, block_size);
|
||||
_mi_stat_counter_increase(&heap->tld->stats.huge_count, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@ -798,7 +795,8 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
|
||||
mi_page_t* page;
|
||||
if (mi_unlikely(size > MI_LARGE_OBJ_SIZE_MAX)) {
|
||||
if (mi_unlikely(size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>)
|
||||
page = NULL;
|
||||
_mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
page = mi_huge_page_alloc(heap,size);
|
||||
@ -808,10 +806,13 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
|
||||
// otherwise find a page with free blocks in our size segregated queues
|
||||
page = mi_find_free_page(heap,size);
|
||||
}
|
||||
if (page == NULL) return NULL; // out of memory
|
||||
if (mi_unlikely(page == NULL)) { // out of memory
|
||||
_mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mi_assert_internal(mi_page_immediate_available(page));
|
||||
mi_assert_internal(page->block_size >= size);
|
||||
mi_assert_internal(mi_page_block_size(page) >= size);
|
||||
|
||||
// and try again, this time succeeding! (i.e. this should never recurse)
|
||||
return _mi_page_malloc(heap, page, size);
|
||||
|
328
src/random.c
Normal file
328
src/random.c
Normal file
@ -0,0 +1,328 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 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.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc-internal.h"
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
We use our own PRNG to keep predictable performance of random number generation
|
||||
and to avoid implementations that use a lock. We only use the OS provided
|
||||
random source to initialize the initial seeds. Since we do not need ultimate
|
||||
performance but we do rely on the security (for secret cookies in secure mode)
|
||||
we use a cryptographically secure generator (chacha20).
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
#define MI_CHACHA_ROUNDS (20) // perhaps use 12 for better performance?
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Chacha20 implementation as the original algorithm with a 64-bit nonce
|
||||
and counter: https://en.wikipedia.org/wiki/Salsa20
|
||||
The input matrix has sixteen 32-bit values:
|
||||
Position 0 to 3: constant key
|
||||
Position 4 to 11: the key
|
||||
Position 12 to 13: the counter.
|
||||
Position 14 to 15: the nonce.
|
||||
|
||||
The implementation uses regular C code which compiles very well on modern compilers.
|
||||
(gcc x64 has no register spills, and clang 6+ uses SSE instructions)
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
static inline uint32_t rotl(uint32_t x, uint32_t shift) {
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
|
||||
static inline void qround(uint32_t x[16], size_t a, size_t b, size_t c, size_t d) {
|
||||
x[a] += x[b]; x[d] = rotl(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = rotl(x[b] ^ x[c], 12);
|
||||
x[a] += x[b]; x[d] = rotl(x[d] ^ x[a], 8);
|
||||
x[c] += x[d]; x[b] = rotl(x[b] ^ x[c], 7);
|
||||
}
|
||||
|
||||
static void chacha_block(mi_random_ctx_t* ctx)
|
||||
{
|
||||
// scramble into `x`
|
||||
uint32_t x[16];
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
x[i] = ctx->input[i];
|
||||
}
|
||||
for (size_t i = 0; i < MI_CHACHA_ROUNDS; i += 2) {
|
||||
qround(x, 0, 4, 8, 12);
|
||||
qround(x, 1, 5, 9, 13);
|
||||
qround(x, 2, 6, 10, 14);
|
||||
qround(x, 3, 7, 11, 15);
|
||||
qround(x, 0, 5, 10, 15);
|
||||
qround(x, 1, 6, 11, 12);
|
||||
qround(x, 2, 7, 8, 13);
|
||||
qround(x, 3, 4, 9, 14);
|
||||
}
|
||||
|
||||
// add scrambled data to the initial state
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
ctx->output[i] = x[i] + ctx->input[i];
|
||||
}
|
||||
ctx->output_available = 16;
|
||||
|
||||
// increment the counter for the next round
|
||||
ctx->input[12] += 1;
|
||||
if (ctx->input[12] == 0) {
|
||||
ctx->input[13] += 1;
|
||||
if (ctx->input[13] == 0) { // and keep increasing into the nonce
|
||||
ctx->input[14] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t chacha_next32(mi_random_ctx_t* ctx) {
|
||||
if (ctx->output_available <= 0) {
|
||||
chacha_block(ctx);
|
||||
ctx->output_available = 16; // (assign again to suppress static analysis warning)
|
||||
}
|
||||
const uint32_t x = ctx->output[16 - ctx->output_available];
|
||||
ctx->output[16 - ctx->output_available] = 0; // reset once the data is handed out
|
||||
ctx->output_available--;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32_t read32(const uint8_t* p, size_t idx32) {
|
||||
const size_t i = 4*idx32;
|
||||
return ((uint32_t)p[i+0] | (uint32_t)p[i+1] << 8 | (uint32_t)p[i+2] << 16 | (uint32_t)p[i+3] << 24);
|
||||
}
|
||||
|
||||
static void chacha_init(mi_random_ctx_t* ctx, const uint8_t key[32], uint64_t nonce)
|
||||
{
|
||||
// since we only use chacha for randomness (and not encryption) we
|
||||
// do not _need_ to read 32-bit values as little endian but we do anyways
|
||||
// just for being compatible :-)
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
const uint8_t* sigma = (uint8_t*)"expand 32-byte k";
|
||||
ctx->input[i] = read32(sigma,i);
|
||||
}
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
ctx->input[i + 4] = read32(key,i);
|
||||
}
|
||||
ctx->input[12] = 0;
|
||||
ctx->input[13] = 0;
|
||||
ctx->input[14] = (uint32_t)nonce;
|
||||
ctx->input[15] = (uint32_t)(nonce >> 32);
|
||||
}
|
||||
|
||||
static void chacha_split(mi_random_ctx_t* ctx, uint64_t nonce, mi_random_ctx_t* ctx_new) {
|
||||
memset(ctx_new, 0, sizeof(*ctx_new));
|
||||
memcpy(ctx_new->input, ctx->input, sizeof(ctx_new->input));
|
||||
ctx_new->input[12] = 0;
|
||||
ctx_new->input[13] = 0;
|
||||
ctx_new->input[14] = (uint32_t)nonce;
|
||||
ctx_new->input[15] = (uint32_t)(nonce >> 32);
|
||||
mi_assert_internal(ctx->input[14] != ctx_new->input[14] || ctx->input[15] != ctx_new->input[15]); // do not reuse nonces!
|
||||
chacha_block(ctx_new);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Random interface
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
#if MI_DEBUG>1
|
||||
static bool mi_random_is_initialized(mi_random_ctx_t* ctx) {
|
||||
return (ctx != NULL && ctx->input[0] != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void _mi_random_split(mi_random_ctx_t* ctx, mi_random_ctx_t* ctx_new) {
|
||||
mi_assert_internal(mi_random_is_initialized(ctx));
|
||||
mi_assert_internal(ctx != ctx_new);
|
||||
chacha_split(ctx, (uintptr_t)ctx_new /*nonce*/, ctx_new);
|
||||
}
|
||||
|
||||
uintptr_t _mi_random_next(mi_random_ctx_t* ctx) {
|
||||
mi_assert_internal(mi_random_is_initialized(ctx));
|
||||
#if MI_INTPTR_SIZE <= 4
|
||||
return chacha_next32(ctx);
|
||||
#elif MI_INTPTR_SIZE == 8
|
||||
return (((uintptr_t)chacha_next32(ctx) << 32) | chacha_next32(ctx));
|
||||
#else
|
||||
# error "define mi_random_next for this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
To initialize a fresh random context we rely on the OS:
|
||||
- Windows : BCryptGenRandom
|
||||
- osX,bsd,wasi: arc4random_buf
|
||||
- Linux : getrandom,/dev/urandom
|
||||
If we cannot get good randomness, we fall back to weak randomness based on a timer and ASLR.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#pragma comment (lib,"bcrypt.lib")
|
||||
#include <bcrypt.h>
|
||||
static bool os_random_buf(void* buf, size_t buf_len) {
|
||||
return (BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)buf_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) >= 0);
|
||||
}
|
||||
/*
|
||||
#define SystemFunction036 NTAPI SystemFunction036
|
||||
#include <NTSecAPI.h>
|
||||
#undef SystemFunction036
|
||||
static bool os_random_buf(void* buf, size_t buf_len) {
|
||||
RtlGenRandom(buf, (ULONG)buf_len);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
#elif defined(ANDROID) || defined(XP_DARWIN) || defined(__APPLE__) || defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__wasi__)
|
||||
#include <stdlib.h>
|
||||
static bool os_random_buf(void* buf, size_t buf_len) {
|
||||
arc4random_buf(buf, buf_len);
|
||||
return true;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
static bool os_random_buf(void* buf, size_t buf_len) {
|
||||
// Modern Linux provides `getrandom` but different distributions either use `sys/random.h` or `linux/random.h`
|
||||
// and for the latter the actual `getrandom` call is not always defined.
|
||||
// (see <https://stackoverflow.com/questions/45237324/why-doesnt-getrandom-compile>)
|
||||
// We therefore use a syscall directly and fall back dynamically to /dev/urandom when needed.
|
||||
#ifdef SYS_getrandom
|
||||
#ifndef GRND_NONBLOCK
|
||||
#define GRND_NONBLOCK (1)
|
||||
#endif
|
||||
static volatile _Atomic(uintptr_t) no_getrandom; // = 0
|
||||
if (mi_atomic_read(&no_getrandom)==0) {
|
||||
ssize_t ret = syscall(SYS_getrandom, buf, buf_len, GRND_NONBLOCK);
|
||||
if (ret >= 0) return (buf_len == (size_t)ret);
|
||||
if (ret != ENOSYS) return false;
|
||||
mi_atomic_write(&no_getrandom,1); // don't call again, and fall back to /dev/urandom
|
||||
}
|
||||
#endif
|
||||
int flags = O_RDONLY;
|
||||
#if defined(O_CLOEXEC)
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
int fd = open("/dev/urandom", flags, 0);
|
||||
if (fd < 0) return false;
|
||||
size_t count = 0;
|
||||
while(count < buf_len) {
|
||||
ssize_t ret = read(fd, (char*)buf + count, buf_len - count);
|
||||
if (ret<=0) {
|
||||
if (errno!=EAGAIN && errno!=EINTR) break;
|
||||
}
|
||||
else {
|
||||
count += ret;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
return (count==buf_len);
|
||||
}
|
||||
#else
|
||||
static bool os_random_buf(void* buf, size_t buf_len) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static uintptr_t os_random_weak(uintptr_t extra_seed) {
|
||||
uintptr_t x = (uintptr_t)&os_random_weak ^ extra_seed; // ASLR makes the address random
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER pcount;
|
||||
QueryPerformanceCounter(&pcount);
|
||||
x ^= (uintptr_t)(pcount.QuadPart);
|
||||
#elif defined(__APPLE__)
|
||||
x ^= (uintptr_t)mach_absolute_time();
|
||||
#else
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
x ^= (uintptr_t)time.tv_sec;
|
||||
x ^= (uintptr_t)time.tv_nsec;
|
||||
#endif
|
||||
// and do a few randomization steps
|
||||
uintptr_t max = ((x ^ (x >> 17)) & 0x0F) + 1;
|
||||
for (uintptr_t i = 0; i < max; i++) {
|
||||
x = _mi_random_shuffle(x);
|
||||
}
|
||||
mi_assert_internal(x != 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
void _mi_random_init(mi_random_ctx_t* ctx) {
|
||||
uint8_t key[32];
|
||||
if (!os_random_buf(key, sizeof(key))) {
|
||||
// if we fail to get random data from the OS, we fall back to a
|
||||
// weak random source based on the current time
|
||||
_mi_warning_message("unable to use secure randomness\n");
|
||||
uintptr_t x = os_random_weak(0);
|
||||
for (size_t i = 0; i < 8; i++) { // key is eight 32-bit words.
|
||||
x = _mi_random_shuffle(x);
|
||||
((uint32_t*)key)[i] = (uint32_t)x;
|
||||
}
|
||||
}
|
||||
chacha_init(ctx, key, (uintptr_t)ctx /*nonce*/ );
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------
|
||||
test vectors from <https://tools.ietf.org/html/rfc8439>
|
||||
----------------------------------------------------------- */
|
||||
/*
|
||||
static bool array_equals(uint32_t* x, uint32_t* y, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (x[i] != y[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void chacha_test(void)
|
||||
{
|
||||
uint32_t x[4] = { 0x11111111, 0x01020304, 0x9b8d6f43, 0x01234567 };
|
||||
uint32_t x_out[4] = { 0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb };
|
||||
qround(x, 0, 1, 2, 3);
|
||||
mi_assert_internal(array_equals(x, x_out, 4));
|
||||
|
||||
uint32_t y[16] = {
|
||||
0x879531e0, 0xc5ecf37d, 0x516461b1, 0xc9a62f8a,
|
||||
0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0x2a5f714c,
|
||||
0x53372767, 0xb00a5631, 0x974c541a, 0x359e9963,
|
||||
0x5c971061, 0x3d631689, 0x2098d9d6, 0x91dbd320 };
|
||||
uint32_t y_out[16] = {
|
||||
0x879531e0, 0xc5ecf37d, 0xbdb886dc, 0xc9a62f8a,
|
||||
0x44c20ef3, 0x3390af7f, 0xd9fc690b, 0xcfacafd2,
|
||||
0xe46bea80, 0xb00a5631, 0x974c541a, 0x359e9963,
|
||||
0x5c971061, 0xccc07c79, 0x2098d9d6, 0x91dbd320 };
|
||||
qround(y, 2, 7, 8, 13);
|
||||
mi_assert_internal(array_equals(y, y_out, 16));
|
||||
|
||||
mi_random_ctx_t r = {
|
||||
{ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
|
||||
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
|
||||
0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
|
||||
0x00000001, 0x09000000, 0x4a000000, 0x00000000 },
|
||||
{0},
|
||||
0
|
||||
};
|
||||
uint32_t r_out[16] = {
|
||||
0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3,
|
||||
0xc7f4d1c7, 0x0368c033, 0x9aaa2204, 0x4e6cd4c3,
|
||||
0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9,
|
||||
0xd19c12b5, 0xb94e16de, 0xe883d0cb, 0x4e3c50a2 };
|
||||
chacha_block(&r);
|
||||
mi_assert_internal(array_equals(r.output, r_out, 16));
|
||||
}
|
||||
*/
|
496
src/region.c
Normal file
496
src/region.c
Normal file
@ -0,0 +1,496 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 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.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
This implements a layer between the raw OS memory (VirtualAlloc/mmap/sbrk/..)
|
||||
and the segment and huge object allocation by mimalloc. There may be multiple
|
||||
implementations of this (one could be the identity going directly to the OS,
|
||||
another could be a simple cache etc), but the current one uses large "regions".
|
||||
In contrast to the rest of mimalloc, the "regions" are shared between threads and
|
||||
need to be accessed using atomic operations.
|
||||
We need this memory layer between the raw OS calls because of:
|
||||
1. on `sbrk` like systems (like WebAssembly) we need our own memory maps in order
|
||||
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 :-( (`malloc-large` tests this). This means we need a cheaper
|
||||
way to reuse memory.
|
||||
3. This layer allows for NUMA aware allocation.
|
||||
|
||||
Possible issues:
|
||||
- (2) can potentially be addressed too with a small cache per thread which is much
|
||||
simpler. Generally though that requires shrinking of huge pages, and may overuse
|
||||
memory per thread. (and is not compatible with `sbrk`).
|
||||
- Since the current regions are per-process, we need atomic operations to
|
||||
claim blocks which may be contended
|
||||
- In the worst case, we need to search the whole region map (16KiB for 256GiB)
|
||||
linearly. At what point will direct OS calls be faster? Is there a way to
|
||||
do this better without adding too much complexity?
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc-internal.h"
|
||||
#include "mimalloc-atomic.h"
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
#include "bitmap.inc.c"
|
||||
|
||||
// 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, 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, bool* is_zero, mi_stats_t* stats);
|
||||
|
||||
// arena.c
|
||||
void _mi_arena_free(void* p, size_t size, size_t memid, mi_stats_t* stats);
|
||||
void* _mi_arena_alloc(size_t size, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld);
|
||||
void* _mi_arena_alloc_aligned(size_t size, size_t alignment, bool* commit, bool* large, bool* is_zero, size_t* memid, mi_os_tld_t* tld);
|
||||
|
||||
|
||||
|
||||
// Constants
|
||||
#if (MI_INTPTR_SIZE==8)
|
||||
#define MI_HEAP_REGION_MAX_SIZE (256 * GiB) // 64KiB for the region map
|
||||
#elif (MI_INTPTR_SIZE==4)
|
||||
#define MI_HEAP_REGION_MAX_SIZE (3 * GiB) // ~ KiB for the region map
|
||||
#else
|
||||
#error "define the maximum heap space allowed for regions on this platform"
|
||||
#endif
|
||||
|
||||
#define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE
|
||||
|
||||
#define MI_REGION_MAX_BLOCKS MI_BITMAP_FIELD_BITS
|
||||
#define MI_REGION_SIZE (MI_SEGMENT_SIZE * MI_BITMAP_FIELD_BITS) // 256MiB (64MiB on 32 bits)
|
||||
#define MI_REGION_MAX (MI_HEAP_REGION_MAX_SIZE / MI_REGION_SIZE) // 1024 (48 on 32 bits)
|
||||
#define MI_REGION_MAX_OBJ_BLOCKS (MI_REGION_MAX_BLOCKS/4) // 64MiB
|
||||
#define MI_REGION_MAX_OBJ_SIZE (MI_REGION_MAX_OBJ_BLOCKS*MI_SEGMENT_SIZE)
|
||||
|
||||
// Region info
|
||||
typedef union mi_region_info_u {
|
||||
uintptr_t value;
|
||||
struct {
|
||||
bool valid; // initialized?
|
||||
bool is_large; // allocated in fixed large/huge OS pages
|
||||
short numa_node; // the associated NUMA node (where -1 means no associated node)
|
||||
} x;
|
||||
} mi_region_info_t;
|
||||
|
||||
|
||||
// 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) info; // mi_region_info_t.value
|
||||
volatile _Atomic(void*) start; // start of the memory area
|
||||
mi_bitmap_field_t in_use; // bit per in-use block
|
||||
mi_bitmap_field_t dirty; // track if non-zero per block
|
||||
mi_bitmap_field_t commit; // track if committed per block
|
||||
mi_bitmap_field_t reset; // track if reset per block
|
||||
volatile _Atomic(uintptr_t) arena_memid; // if allocated from a (huge page) arena
|
||||
uintptr_t padding; // round to 8 fields
|
||||
} mem_region_t;
|
||||
|
||||
// The region map
|
||||
static mem_region_t regions[MI_REGION_MAX];
|
||||
|
||||
// Allocated regions
|
||||
static volatile _Atomic(uintptr_t) regions_count; // = 0;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Utility functions
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// Blocks (of 4MiB) needed for the given size.
|
||||
static size_t mi_region_block_count(size_t size) {
|
||||
return _mi_divide_up(size, MI_SEGMENT_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
// Return a rounded commit/reset size such that we don't fragment large OS pages into small ones.
|
||||
static size_t mi_good_commit_size(size_t size) {
|
||||
if (size > (SIZE_MAX - _mi_os_large_page_size())) return size;
|
||||
return _mi_align_up(size, _mi_os_large_page_size());
|
||||
}
|
||||
*/
|
||||
|
||||
// Return if a pointer points into a region reserved by us.
|
||||
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 = mi_atomic_read_ptr_relaxed(uint8_t,®ions[i].start);
|
||||
if (start != NULL && (uint8_t*)p >= start && (uint8_t*)p < start + MI_REGION_SIZE) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void* mi_region_blocks_start(const mem_region_t* region, mi_bitmap_index_t bit_idx) {
|
||||
uint8_t* start = mi_atomic_read_ptr(uint8_t,®ion->start);
|
||||
mi_assert_internal(start != NULL);
|
||||
return (start + (bit_idx * MI_SEGMENT_SIZE));
|
||||
}
|
||||
|
||||
static size_t mi_memid_create(mem_region_t* region, mi_bitmap_index_t bit_idx) {
|
||||
mi_assert_internal(bit_idx < MI_BITMAP_FIELD_BITS);
|
||||
size_t idx = region - regions;
|
||||
mi_assert_internal(®ions[idx] == region);
|
||||
return (idx*MI_BITMAP_FIELD_BITS + bit_idx)<<1;
|
||||
}
|
||||
|
||||
static size_t mi_memid_create_from_arena(size_t arena_memid) {
|
||||
return (arena_memid << 1) | 1;
|
||||
}
|
||||
|
||||
|
||||
static bool mi_memid_is_arena(size_t id, mem_region_t** region, mi_bitmap_index_t* bit_idx, size_t* arena_memid) {
|
||||
if ((id&1)==1) {
|
||||
if (arena_memid != NULL) *arena_memid = (id>>1);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
size_t idx = (id >> 1) / MI_BITMAP_FIELD_BITS;
|
||||
*bit_idx = (mi_bitmap_index_t)(id>>1) % MI_BITMAP_FIELD_BITS;
|
||||
*region = ®ions[idx];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Allocate a region is allocated from the OS (or an arena)
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
static bool mi_region_try_alloc_os(size_t blocks, bool commit, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld)
|
||||
{
|
||||
// not out of regions yet?
|
||||
if (mi_atomic_read_relaxed(®ions_count) >= MI_REGION_MAX - 1) return false;
|
||||
|
||||
// try to allocate a fresh region from the OS
|
||||
bool region_commit = (commit && mi_option_is_enabled(mi_option_eager_region_commit));
|
||||
bool region_large = (commit && allow_large);
|
||||
bool is_zero = false;
|
||||
size_t arena_memid = 0;
|
||||
void* const start = _mi_arena_alloc_aligned(MI_REGION_SIZE, MI_SEGMENT_ALIGN, ®ion_commit, ®ion_large, &is_zero, &arena_memid, tld);
|
||||
if (start == NULL) return false;
|
||||
mi_assert_internal(!(region_large && !allow_large));
|
||||
mi_assert_internal(!region_large || region_commit);
|
||||
|
||||
// claim a fresh slot
|
||||
const uintptr_t idx = mi_atomic_increment(®ions_count);
|
||||
if (idx >= MI_REGION_MAX) {
|
||||
mi_atomic_decrement(®ions_count);
|
||||
_mi_arena_free(start, MI_REGION_SIZE, arena_memid, tld->stats);
|
||||
_mi_warning_message("maximum regions used: %zu GiB (perhaps recompile with a larger setting for MI_HEAP_REGION_MAX_SIZE)", _mi_divide_up(MI_HEAP_REGION_MAX_SIZE, GiB));
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocated, initialize and claim the initial blocks
|
||||
mem_region_t* r = ®ions[idx];
|
||||
r->arena_memid = arena_memid;
|
||||
mi_atomic_write(&r->in_use, 0);
|
||||
mi_atomic_write(&r->dirty, (is_zero ? 0 : MI_BITMAP_FIELD_FULL));
|
||||
mi_atomic_write(&r->commit, (region_commit ? MI_BITMAP_FIELD_FULL : 0));
|
||||
mi_atomic_write(&r->reset, 0);
|
||||
*bit_idx = 0;
|
||||
mi_bitmap_claim(&r->in_use, 1, blocks, *bit_idx, NULL);
|
||||
mi_atomic_write_ptr(uint8_t*,&r->start, start);
|
||||
|
||||
// and share it
|
||||
mi_region_info_t info;
|
||||
info.x.valid = true;
|
||||
info.x.is_large = region_large;
|
||||
info.x.numa_node = (short)_mi_os_numa_node(tld);
|
||||
mi_atomic_write(&r->info, info.value); // now make it available to others
|
||||
*region = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Try to claim blocks in suitable regions
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
static bool mi_region_is_suitable(const mem_region_t* region, int numa_node, bool allow_large ) {
|
||||
// initialized at all?
|
||||
mi_region_info_t info;
|
||||
info.value = mi_atomic_read_relaxed(®ion->info);
|
||||
if (info.value==0) return false;
|
||||
|
||||
// numa correct
|
||||
if (numa_node >= 0) { // use negative numa node to always succeed
|
||||
int rnode = info.x.numa_node;
|
||||
if (rnode >= 0 && rnode != numa_node) return false;
|
||||
}
|
||||
|
||||
// check allow-large
|
||||
if (!allow_large && info.x.is_large) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool mi_region_try_claim(int numa_node, size_t blocks, bool allow_large, mem_region_t** region, mi_bitmap_index_t* bit_idx, mi_os_tld_t* tld)
|
||||
{
|
||||
// try all regions for a free slot
|
||||
const size_t count = mi_atomic_read(®ions_count);
|
||||
size_t idx = tld->region_idx; // Or start at 0 to reuse low addresses? Starting at 0 seems to increase latency though
|
||||
for (size_t visited = 0; visited < count; visited++, idx++) {
|
||||
if (idx >= count) idx = 0; // wrap around
|
||||
mem_region_t* r = ®ions[idx];
|
||||
// if this region suits our demand (numa node matches, large OS page matches)
|
||||
if (mi_region_is_suitable(r, numa_node, allow_large)) {
|
||||
// then try to atomically claim a segment(s) in this region
|
||||
if (mi_bitmap_try_find_claim_field(&r->in_use, 0, blocks, bit_idx)) {
|
||||
tld->region_idx = idx; // remember the last found position
|
||||
*region = r;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void* mi_region_try_alloc(size_t blocks, bool* commit, bool* is_large, bool* is_zero, size_t* memid, mi_os_tld_t* tld)
|
||||
{
|
||||
mi_assert_internal(blocks <= MI_BITMAP_FIELD_BITS);
|
||||
mem_region_t* region;
|
||||
mi_bitmap_index_t bit_idx;
|
||||
const int numa_node = (_mi_os_numa_node_count() <= 1 ? -1 : _mi_os_numa_node(tld));
|
||||
// try to claim in existing regions
|
||||
if (!mi_region_try_claim(numa_node, blocks, *is_large, ®ion, &bit_idx, tld)) {
|
||||
// otherwise try to allocate a fresh region and claim in there
|
||||
if (!mi_region_try_alloc_os(blocks, *commit, *is_large, ®ion, &bit_idx, tld)) {
|
||||
// out of regions or memory
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// found a region and claimed `blocks` at `bit_idx`, initialize them now
|
||||
mi_assert_internal(region != NULL);
|
||||
mi_assert_internal(mi_bitmap_is_claimed(®ion->in_use, 1, blocks, bit_idx));
|
||||
|
||||
mi_region_info_t info;
|
||||
info.value = mi_atomic_read(®ion->info);
|
||||
uint8_t* start = mi_atomic_read_ptr(uint8_t,®ion->start);
|
||||
mi_assert_internal(!(info.x.is_large && !*is_large));
|
||||
mi_assert_internal(start != NULL);
|
||||
|
||||
*is_zero = mi_bitmap_claim(®ion->dirty, 1, blocks, bit_idx, NULL);
|
||||
*is_large = info.x.is_large;
|
||||
*memid = mi_memid_create(region, bit_idx);
|
||||
void* p = start + (mi_bitmap_index_bit_in_field(bit_idx) * MI_SEGMENT_SIZE);
|
||||
|
||||
// commit
|
||||
if (*commit) {
|
||||
// ensure commit
|
||||
bool any_uncommitted;
|
||||
mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, &any_uncommitted);
|
||||
if (any_uncommitted) {
|
||||
mi_assert_internal(!info.x.is_large);
|
||||
bool commit_zero;
|
||||
_mi_mem_commit(p, blocks * MI_SEGMENT_SIZE, &commit_zero, tld);
|
||||
if (commit_zero) *is_zero = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no need to commit, but check if already fully committed
|
||||
*commit = mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx);
|
||||
}
|
||||
mi_assert_internal(!*commit || mi_bitmap_is_claimed(®ion->commit, 1, blocks, bit_idx));
|
||||
|
||||
// unreset reset blocks
|
||||
if (mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx)) {
|
||||
// some blocks are still reset
|
||||
mi_assert_internal(!info.x.is_large);
|
||||
mi_assert_internal(!mi_option_is_enabled(mi_option_eager_commit) || *commit || mi_option_get(mi_option_eager_commit_delay) > 0);
|
||||
mi_bitmap_unclaim(®ion->reset, 1, blocks, bit_idx);
|
||||
if (*commit || !mi_option_is_enabled(mi_option_reset_decommits)) { // only if needed
|
||||
bool reset_zero = false;
|
||||
_mi_mem_unreset(p, blocks * MI_SEGMENT_SIZE, &reset_zero, tld);
|
||||
if (reset_zero) *is_zero = true;
|
||||
}
|
||||
}
|
||||
mi_assert_internal(!mi_bitmap_is_any_claimed(®ion->reset, 1, blocks, bit_idx));
|
||||
|
||||
#if (MI_DEBUG>=2)
|
||||
if (*commit) { ((uint8_t*)p)[0] = 0; }
|
||||
#endif
|
||||
|
||||
// and return the allocation
|
||||
mi_assert_internal(p != NULL);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Allocation
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// 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, bool* is_zero, size_t* memid, mi_os_tld_t* tld)
|
||||
{
|
||||
mi_assert_internal(memid != NULL && tld != NULL);
|
||||
mi_assert_internal(size > 0);
|
||||
*memid = 0;
|
||||
*is_zero = false;
|
||||
bool default_large = false;
|
||||
if (large==NULL) large = &default_large; // ensure `large != NULL`
|
||||
if (size == 0) return NULL;
|
||||
size = _mi_align_up(size, _mi_os_page_size());
|
||||
|
||||
// allocate from regions if possible
|
||||
void* p = NULL;
|
||||
size_t arena_memid;
|
||||
const size_t blocks = mi_region_block_count(size);
|
||||
if (blocks <= MI_REGION_MAX_OBJ_BLOCKS && alignment <= MI_SEGMENT_ALIGN) {
|
||||
p = mi_region_try_alloc(blocks, commit, large, is_zero, memid, tld);
|
||||
if (p == NULL) {
|
||||
_mi_warning_message("unable to allocate from region: size %zu\n", size);
|
||||
}
|
||||
}
|
||||
if (p == NULL) {
|
||||
// and otherwise fall back to the OS
|
||||
p = _mi_arena_alloc_aligned(size, alignment, commit, large, is_zero, &arena_memid, tld);
|
||||
*memid = mi_memid_create_from_arena(arena_memid);
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
mi_assert_internal((uintptr_t)p % alignment == 0);
|
||||
#if (MI_DEBUG>=2)
|
||||
if (*commit) { ((uint8_t*)p)[0] = 0; } // ensure the memory is committed
|
||||
#endif
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Free
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// Free previously allocated memory with a given id.
|
||||
void _mi_mem_free(void* p, size_t size, size_t id, bool full_commit, bool any_reset, mi_os_tld_t* tld) {
|
||||
mi_assert_internal(size > 0 && tld != NULL);
|
||||
if (p==NULL) return;
|
||||
if (size==0) return;
|
||||
size = _mi_align_up(size, _mi_os_page_size());
|
||||
|
||||
size_t arena_memid = 0;
|
||||
mi_bitmap_index_t bit_idx;
|
||||
mem_region_t* region;
|
||||
if (mi_memid_is_arena(id,®ion,&bit_idx,&arena_memid)) {
|
||||
// was a direct arena allocation, pass through
|
||||
_mi_arena_free(p, size, arena_memid, tld->stats);
|
||||
}
|
||||
else {
|
||||
// allocated in a region
|
||||
mi_assert_internal(size <= MI_REGION_MAX_OBJ_SIZE); if (size > MI_REGION_MAX_OBJ_SIZE) return;
|
||||
const size_t blocks = mi_region_block_count(size);
|
||||
mi_assert_internal(blocks + bit_idx <= MI_BITMAP_FIELD_BITS);
|
||||
mi_region_info_t info;
|
||||
info.value = mi_atomic_read(®ion->info);
|
||||
mi_assert_internal(info.value != 0);
|
||||
void* blocks_start = mi_region_blocks_start(region, bit_idx);
|
||||
mi_assert_internal(blocks_start == p); // not a pointer in our area?
|
||||
mi_assert_internal(bit_idx + blocks <= MI_BITMAP_FIELD_BITS);
|
||||
if (blocks_start != p || bit_idx + blocks > MI_BITMAP_FIELD_BITS) return; // or `abort`?
|
||||
|
||||
// committed?
|
||||
if (full_commit && (size % MI_SEGMENT_SIZE) == 0) {
|
||||
mi_bitmap_claim(®ion->commit, 1, blocks, bit_idx, NULL);
|
||||
}
|
||||
|
||||
if (any_reset) {
|
||||
// set the is_reset bits if any pages were reset
|
||||
mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, NULL);
|
||||
}
|
||||
|
||||
// reset the blocks to reduce the working set.
|
||||
if (!info.x.is_large && mi_option_is_enabled(mi_option_segment_reset)
|
||||
&& (mi_option_is_enabled(mi_option_eager_commit) ||
|
||||
mi_option_is_enabled(mi_option_reset_decommits))) // cannot reset halfway committed segments, use only `option_page_reset` instead
|
||||
{
|
||||
bool any_unreset;
|
||||
mi_bitmap_claim(®ion->reset, 1, blocks, bit_idx, &any_unreset);
|
||||
if (any_unreset) {
|
||||
_mi_abandoned_await_readers(); // ensure no more pending write (in case reset = decommit)
|
||||
_mi_mem_reset(p, blocks * MI_SEGMENT_SIZE, tld);
|
||||
}
|
||||
}
|
||||
|
||||
// and unclaim
|
||||
bool all_unclaimed = mi_bitmap_unclaim(®ion->in_use, 1, blocks, bit_idx);
|
||||
mi_assert_internal(all_unclaimed); UNUSED(all_unclaimed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
collection
|
||||
-----------------------------------------------------------------------------*/
|
||||
void _mi_mem_collect(mi_os_tld_t* tld) {
|
||||
// free every region that has no segments in use.
|
||||
uintptr_t rcount = mi_atomic_read_relaxed(®ions_count);
|
||||
for (size_t i = 0; i < rcount; i++) {
|
||||
mem_region_t* region = ®ions[i];
|
||||
if (mi_atomic_read_relaxed(®ion->info) != 0) {
|
||||
// if no segments used, try to claim the whole region
|
||||
uintptr_t m;
|
||||
do {
|
||||
m = mi_atomic_read_relaxed(®ion->in_use);
|
||||
} while(m == 0 && !mi_atomic_cas_weak(®ion->in_use, MI_BITMAP_FIELD_FULL, 0 ));
|
||||
if (m == 0) {
|
||||
// on success, free the whole region
|
||||
uint8_t* start = mi_atomic_read_ptr(uint8_t,®ions[i].start);
|
||||
size_t arena_memid = mi_atomic_read_relaxed(®ions[i].arena_memid);
|
||||
memset(®ions[i], 0, sizeof(mem_region_t));
|
||||
// and release the whole region
|
||||
mi_atomic_write(®ion->info, 0);
|
||||
if (start != NULL) { // && !_mi_os_is_huge_reserved(start)) {
|
||||
_mi_abandoned_await_readers(); // ensure no pending reads
|
||||
_mi_arena_free(start, MI_REGION_SIZE, arena_memid, tld->stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
Other
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
bool _mi_mem_reset(void* p, size_t size, mi_os_tld_t* tld) {
|
||||
return _mi_os_reset(p, size, tld->stats);
|
||||
}
|
||||
|
||||
bool _mi_mem_unreset(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld) {
|
||||
return _mi_os_unreset(p, size, is_zero, tld->stats);
|
||||
}
|
||||
|
||||
bool _mi_mem_commit(void* p, size_t size, bool* is_zero, mi_os_tld_t* tld) {
|
||||
return _mi_os_commit(p, size, is_zero, tld->stats);
|
||||
}
|
||||
|
||||
bool _mi_mem_decommit(void* p, size_t size, mi_os_tld_t* tld) {
|
||||
return _mi_os_decommit(p, size, tld->stats);
|
||||
}
|
||||
|
||||
bool _mi_mem_protect(void* p, size_t size) {
|
||||
return _mi_os_protect(p, size);
|
||||
}
|
||||
|
||||
bool _mi_mem_unprotect(void* p, size_t size) {
|
||||
return _mi_os_unprotect(p, size);
|
||||
}
|
1105
src/segment.c
1105
src/segment.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user