Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

supports mimalloc for ARC/ORC (1.15x ~ 1.22x speedup booting the compiler) #20359

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions config/config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@ cppDefine "NAN_INFINITY"
cppDefine "INF"
cppDefine "NAN"



let
mimallocPath = "lib/system/mm/mimalloc/"
# Quote the paths so we support paths with spaces
mimallocStatic = "mimallocStatic=\"" & (mimallocPath & "src/static.c") & '"'
mimallocIncludePath = "mimallocIncludePath=\"" & (mimallocPath & "/include") & '"'

# So we can compile mimalloc from the patched files
switch("define", mimallocStatic)
switch("define", mimallocIncludePath)

# Not sure if we really need those or not, but Mimalloc uses them
case get("cc")
of "gcc", "clang", "icc", "icl":
switch("passC", "-ftls-model=initial-exec -fno-builtin-malloc")
else:
discard

when defined(nimStrictMode):
# xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI.

Expand Down
2 changes: 2 additions & 0 deletions koch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ proc runCI(cmd: string) =
# the BSDs are overwhelmed already, so only run this test on the other machines:
kochExecFold("Boot Nim ORC", "boot -d:release --mm:orc --lib:lib")

kochExecFold("Boot Nim ORC with mimalloc", "boot -d:release --mm:orc --lib:lib -d:useMalloc")
ringabout marked this conversation as resolved.
Show resolved Hide resolved

proc testUnixInstall(cmdLineRest: string) =
csource("-d:danger" & cmdLineRest)
xz(false, cmdLineRest)
Expand Down
2 changes: 1 addition & 1 deletion lib/system/memalloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ when defined(js):
proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = discard


when hasAlloc and hasThreadSupport and not defined(useMalloc):
when hasAlloc and hasThreadSupport and not defined(useMalloc) and not defined(useMimalloc):
proc getOccupiedSharedMem*(): int {.rtl.}
## Returns the number of bytes that are owned by the process
## on the shared heap and hold data. This is only available when
Expand Down
2 changes: 1 addition & 1 deletion lib/system/mm/malloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@ proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var MemRegion) = discard
proc deallocOsPages() = discard

{.pop.}
{.pop.}
127 changes: 127 additions & 0 deletions lib/system/mm/mimalloc.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
when not defined(vcc):
# Generic GCC-like arguments
{.passc: "-DNDEBUG -fvisibility=hidden".}
# shell32 user32 aren't needed for static linking from my testing
when defined(windows):
{.passl: "-lpsapi -lbcrypt -ladvapi32".}
else:
# Specifically for VCC which has different syntax
{.passc: "/DNDEBUG".}
{.passl: "psapi.lib bcrypt.lib advapi32.lib".}

const
mimallocStatic {.strdefine.} = "empty"
mimallocIncludePath {.strdefine.} = "empty"
# Can't import std/strutils in this file so we unquote the manual way
mimallocStaticNoQuote = block:
var c: string
for i in 1..<mimallocStatic.len - 1:
c.add mimallocStatic[i]
c

{.passc: "-I" & mimallocIncludePath.}
{.passl: "-I" & mimallocIncludePath.}
{.compile: mimallocStaticNoQuote.}

{.push stackTrace: off.}

proc mi_malloc(size: csize_t): pointer {.importc, header: "mimalloc.h".}
proc mi_calloc(nmemb: csize_t, size: csize_t): pointer {.importc, header: "mimalloc.h".}
proc mi_realloc(pt: pointer, size: csize_t): pointer {.importc, header: "mimalloc.h".}
proc mi_free(p: pointer) {.importc, header: "mimalloc.h".}


proc allocImpl(size: Natural): pointer =
result = mi_malloc(size.csize_t)
when defined(zephyr):
if result == nil:
raiseOutOfMem()

proc alloc0Impl(size: Natural): pointer =
result = mi_calloc(size.csize_t, 1)
when defined(zephyr):
if result == nil:
raiseOutOfMem()

proc reallocImpl(p: pointer, newSize: Natural): pointer =
result = mi_realloc(p, newSize.csize_t)
when defined(zephyr):
if result == nil:
raiseOutOfMem()

proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer =
result = realloc(p, newSize.csize_t)
if newSize > oldSize:
zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize)

proc deallocImpl(p: pointer) =
mi_free(p)


# The shared allocators map on the regular ones

proc allocSharedImpl(size: Natural): pointer =
allocImpl(size)

proc allocShared0Impl(size: Natural): pointer =
alloc0Impl(size)

proc reallocSharedImpl(p: pointer, newSize: Natural): pointer =
reallocImpl(p, newSize)

proc reallocShared0Impl(p: pointer, oldsize, newSize: Natural): pointer =
realloc0Impl(p, oldSize, newSize)

proc deallocSharedImpl(p: pointer) = deallocImpl(p)


# Empty stubs for the GC

proc GC_disable() = discard
proc GC_enable() = discard

when not defined(gcOrc):
proc GC_fullCollect() = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard

proc GC_setStrategy(strategy: GC_Strategy) = discard

proc getOccupiedMem(): int = discard
proc getFreeMem(): int = discard
proc getTotalMem(): int = discard

proc nimGC_setStackBottom(theStackBottom: pointer) = discard

proc initGC() = discard

proc newObjNoInit(typ: PNimType, size: int): pointer =
result = alloc(size)

proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize)

proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard

when not defined(gcDestructors):
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src

proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
deprecated: "old compiler compat".} = asgnRef(dest, src)

type
MemRegion = object

proc alloc(r: var MemRegion, size: int): pointer =
result = alloc(size)
proc alloc0Impl(r: var MemRegion, size: int): pointer =
result = alloc0Impl(size)
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var MemRegion) = discard
proc deallocOsPages() = discard

{.pop.}
Loading