Skip to content

Commit

Permalink
Added 'getAllocStats()' to get low level alloc/dealloc counters. Enab…
Browse files Browse the repository at this point in the history
…le with -d:allocStats
  • Loading branch information
Ico Doornekamp committed Jan 20, 2020
1 parent 38c5712 commit 00742d2
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 90 deletions.
20 changes: 10 additions & 10 deletions lib/system/alloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1002,19 +1002,19 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =

proc deallocOsPages = deallocOsPages(allocator)

proc alloc(size: Natural): pointer =
proc allocImpl(size: Natural): pointer =
result = alloc(allocator, size)

proc alloc0(size: Natural): pointer =
proc alloc0Impl(size: Natural): pointer =
result = alloc0(allocator, size)

proc dealloc(p: pointer) =
proc deallocImpl(p: pointer) =
dealloc(allocator, p)

proc realloc(p: pointer, newSize: Natural): pointer =
proc reallocImpl(p: pointer, newSize: Natural): pointer =
result = realloc(allocator, p, newSize)

proc realloc0(p: pointer, oldSize, newSize: Natural): pointer =
proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer =
result = realloc(allocator, p, newSize)
if newSize > oldSize:
zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize)
Expand Down Expand Up @@ -1044,35 +1044,35 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
var heapLock: SysLock
initSysLock(heapLock)

proc allocShared(size: Natural): pointer =
proc allocSharedImpl(size: Natural): pointer =
when hasThreadSupport:
acquireSys(heapLock)
result = alloc(sharedHeap, size)
releaseSys(heapLock)
else:
result = alloc(size)

proc allocShared0(size: Natural): pointer =
proc allocShared0Impl(size: Natural): pointer =
result = allocShared(size)
zeroMem(result, size)

proc deallocShared(p: pointer) =
proc deallocSharedImpl(p: pointer) =
when hasThreadSupport:
acquireSys(heapLock)
dealloc(sharedHeap, p)
releaseSys(heapLock)
else:
dealloc(p)

proc reallocShared(p: pointer, newSize: Natural): pointer =
proc reallocSharedImpl(p: pointer, newSize: Natural): pointer =
when hasThreadSupport:
acquireSys(heapLock)
result = realloc(sharedHeap, p, newSize)
releaseSys(heapLock)
else:
result = realloc(p, newSize)

proc reallocShared0(p: pointer, oldSize, newSize: Natural): pointer =
proc reallocShared0Impl(p: pointer, oldSize, newSize: Natural): pointer =
when hasThreadSupport:
acquireSys(heapLock)
result = realloc0(sharedHeap, p, oldSize, newSize)
Expand Down
20 changes: 10 additions & 10 deletions lib/system/gc_regions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,21 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
deprecated: "old compiler compat".} = asgnRef(dest, src)

proc alloc(size: Natural): pointer =
proc allocImpl(size: Natural): pointer =
result = c_malloc(cast[csize_t](size))
if result == nil: raiseOutOfMem()
proc alloc0(size: Natural): pointer =
proc alloc0Impl(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
proc realloc(p: pointer, newsize: Natural): pointer =
proc reallocImpl(p: pointer, newsize: Natural): pointer =
result = c_realloc(p, cast[csize_t](newsize))
if result == nil: raiseOutOfMem()
proc realloc0(p: pointer, oldsize, newsize: Natural): pointer =
proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
result = c_realloc(p, cast[csize_t](newsize))
if result == nil: raiseOutOfMem()
if newsize > oldsize:
zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
proc dealloc(p: pointer) = c_free(p)
proc deallocImpl(p: pointer) = c_free(p)

proc alloc0(r: var MemRegion; size: Natural): pointer =
# ignore the region. That is correct for the channels module
Expand All @@ -405,21 +405,21 @@ proc alloc(r: var MemRegion; size: Natural): pointer =

proc dealloc(r: var MemRegion; p: pointer) = dealloc(p)

proc allocShared(size: Natural): pointer =
proc allocSharedImpl(size: Natural): pointer =
result = c_malloc(cast[csize_t](size))
if result == nil: raiseOutOfMem()
proc allocShared0(size: Natural): pointer =
proc allocShared0Impl(size: Natural): pointer =
result = alloc(size)
zeroMem(result, size)
proc reallocShared(p: pointer, newsize: Natural): pointer =
proc reallocSharedImpl(p: pointer, newsize: Natural): pointer =
result = c_realloc(p, cast[csize_t](newsize))
if result == nil: raiseOutOfMem()
proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer =
proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer =
result = c_realloc(p, cast[csize_t](newsize))
if result == nil: raiseOutOfMem()
if newsize > oldsize:
zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
proc deallocShared(p: pointer) = c_free(p)
proc deallocSharedImpl(p: pointer) = c_free(p)

when hasThreadSupport:
proc getFreeSharedMem(): int = 0
Expand Down
92 changes: 77 additions & 15 deletions lib/system/memalloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,48 @@ when notJSnotNims:
## otherwise. Like any procedure dealing with raw memory this is
## **unsafe**.

when hasAlloc:
proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
when hasAlloc and not defined(js):

proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
proc alloc0Impl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
proc deallocImpl*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].}
proc reallocImpl*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
proc realloc0Impl*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}

proc allocSharedImpl*(size: Natural): pointer {.noconv, compilerproc, rtl, benign, raises: [], tags: [].}
proc allocShared0Impl*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
proc deallocSharedImpl*(p: pointer) {.noconv, rtl, benign, raises: [], tags: [].}
proc reallocSharedImpl*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
proc reallocShared0Impl*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}

# Allocator statistics for memory leak tests

{.push stackTrace: off.}

type AllocStats* = object
allocCount: int
deallocCount: int

proc `-`*(a, b: AllocStats): AllocStats =
result.allocCount = a.allocCount - b.allocCount
result.deallocCount = a.deallocCount - b.deallocCount

template dumpAllocstats*(code: untyped) =
let stats1 = getAllocStats()
code
let stats2 = getAllocStats()
echo $(stats2 - stats1)

when defined(allocStats):
var stats: AllocStats
template incStat(what: untyped) = inc stats.what
proc getAllocStats*(): AllocStats = stats

else:
template incStat(what: untyped) = discard
proc getAllocStats*(): AllocStats = discard

template alloc*(size: Natural): pointer =
## Allocates a new memory block with at least ``size`` bytes.
##
## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
Expand All @@ -47,6 +87,9 @@ when hasAlloc:
##
## See also:
## * `alloc0 <#alloc0,Natural>`_
incStat(allocCount)
allocImpl(size)

proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
##
Expand All @@ -62,7 +105,7 @@ when hasAlloc:
## * `create <#create,typedesc>`_
cast[ptr T](alloc(T.sizeof * size))

proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
template alloc0*(size: Natural): pointer =
## Allocates a new memory block with at least ``size`` bytes.
##
## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
Expand All @@ -72,6 +115,9 @@ when hasAlloc:
##
## The allocated memory belongs to its allocating thread!
## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap.
incStat(allocCount)
alloc0Impl(size)

proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
##
Expand All @@ -84,8 +130,7 @@ when hasAlloc:
## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap.
cast[ptr T](alloc0(sizeof(T) * size))

proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
template realloc*(p: pointer, newSize: Natural): pointer =
## Grows or shrinks a given memory block.
##
## If `p` is **nil** then a new memory block is returned.
Expand All @@ -97,8 +142,9 @@ when hasAlloc:
## The allocated memory belongs to its allocating thread!
## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
## from a shared heap.
proc realloc0*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
reallocImpl(p, newSize)

template realloc0*(p: pointer, oldSize, newSize: Natural): pointer =
## Grows or shrinks a given memory block.
##
## If `p` is **nil** then a new memory block is returned.
Expand All @@ -113,6 +159,8 @@ when hasAlloc:
## The allocated memory belongs to its allocating thread!
## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
## from a shared heap.
realloc0Impl(p, oldSize, newSize)

proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} =
## Grows or shrinks a given memory block.
##
Expand All @@ -126,7 +174,7 @@ when hasAlloc:
## from a shared heap.
cast[ptr T](realloc(p, T.sizeof * newSize))

proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].}
template dealloc*(p: pointer) =
## Frees the memory allocated with ``alloc``, ``alloc0`` or
## ``realloc``.
##
Expand All @@ -137,8 +185,10 @@ when hasAlloc:
##
## The freed memory must belong to its allocating thread!
## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap.
incStat(deallocCount)
deallocImpl(p)

proc allocShared*(size: Natural): pointer {.noconv, compilerproc, rtl, benign, raises: [], tags: [].}
template allocShared*(size: Natural): pointer =
## Allocates a new memory block on the shared heap with at
## least ``size`` bytes.
##
Expand All @@ -151,6 +201,9 @@ when hasAlloc:
##
## See also:
## `allocShared0 <#allocShared0,Natural>`_.
incStat(allocCount)
allocSharedImpl(size)

proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [],
benign, raises: [].} =
## Allocates a new memory block on the shared heap with at
Expand All @@ -167,7 +220,7 @@ when hasAlloc:
## * `createShared <#createShared,typedesc>`_
cast[ptr T](allocShared(T.sizeof * size))

proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
template allocShared0*(size: Natural): pointer =
## Allocates a new memory block on the shared heap with at
## least ``size`` bytes.
##
Expand All @@ -178,6 +231,9 @@ when hasAlloc:
## The block is initialized with all bytes
## containing zero, so it is somewhat safer than
## `allocShared <#allocShared,Natural>`_.
incStat(allocCount)
allocShared0Impl(size)

proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
## Allocates a new memory block on the shared heap with at
## least ``T.sizeof * size`` bytes.
Expand All @@ -191,8 +247,7 @@ when hasAlloc:
## `createSharedU <#createSharedU,typedesc>`_.
cast[ptr T](allocShared0(T.sizeof * size))

proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
template reallocShared*(p: pointer, newSize: Natural): pointer =
## Grows or shrinks a given memory block on the heap.
##
## If `p` is **nil** then a new memory block is returned.
Expand All @@ -201,8 +256,9 @@ when hasAlloc:
## ``deallocShared(p)``.
## In other cases the block has to be freed with
## `deallocShared <#deallocShared,pointer>`_.
proc reallocShared0*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
reallocSharedImpl(p, newSize)

template reallocShared0*(p: pointer, oldSize, newSize: Natural): pointer =
## Grows or shrinks a given memory block on the heap.
##
## When growing, the new bytes of the block is initialized with all bytes
Expand All @@ -214,6 +270,8 @@ when hasAlloc:
## ``deallocShared(p)``.
## In other cases the block has to be freed with
## `deallocShared <#deallocShared,pointer>`_.
reallocShared0Impl(p, oldSize, newSize)

proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} =
## Grows or shrinks a given memory block on the heap.
##
Expand All @@ -225,14 +283,17 @@ when hasAlloc:
## `freeShared <#freeShared,ptr.T>`_.
cast[ptr T](reallocShared(p, T.sizeof * newSize))

proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].}
proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} =
## Frees the memory allocated with ``allocShared``, ``allocShared0`` or
## ``reallocShared``.
##
## **This procedure is dangerous!**
## If one forgets to free the memory a leak occurs; if one tries to
## access freed memory (or just freeing it twice!) a core dump may happen
## or other memory may be corrupted.
incStat(deallocCount)
deallocSharedImpl(p)

proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} =
## Frees the memory allocated with ``createShared``, ``createSharedU`` or
## ``resizeShared``.
Expand All @@ -243,6 +304,7 @@ when hasAlloc:
## or other memory may be corrupted.
deallocShared(p)

{.pop.}

# GC interface:

Expand Down
Loading

0 comments on commit 00742d2

Please sign in to comment.