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

Elide memtrace when disabled #97

Merged
merged 7 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 4 additions & 4 deletions src/playdate/api.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{.push raises: [].}

import macros
import std/importutils
import std/importutils, util/initreqs

import bindings/api
import bindings/[api, initreqs]
export api

import graphics, system, file, sprite, display, sound, scoreboards, lua, json, utils, types, nineslice
Expand All @@ -15,9 +15,9 @@ macro initSDK*() =

proc eventHandler(playdateAPI: ptr PlaydateAPI, event: PDSystemEvent, arg: uint32): cint {.cdecl, exportc.} =
privateAccess(PlaydateSys)
privateAccess(PlaydateFile)
if event == kEventInit:
when declared(setupRealloc):
setupRealloc(playdateAPI.system.realloc)
initPrereqs(playdateAPI.system.realloc, playdateAPI.system.logToConsole)
NimMain()
api.playdate = playdateAPI
handler(event, arg)
Expand Down
11 changes: 7 additions & 4 deletions src/playdate/bindings/graphics.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{.push raises: [].}

import utils, types
import utils, types, ../util/initreqs

type LCDRect* {.importc: "LCDRect", header: "pd_api.h".} = object
left* {.importc.}: int # int32?
Expand Down Expand Up @@ -74,7 +74,8 @@ type LCDFontPtr {.importc: "LCDFont*", header: "pd_api.h".} = pointer
type LCDFontObj = object
resource: LCDFontPtr

proc `=destroy`(this: var LCDFontObj) = deallocImpl(this.resource)
proc `=destroy`(this: var LCDFontObj) =
discard pdrealloc(this.resource, 0)

type LCDFont* = ref LCDFontObj

Expand All @@ -85,15 +86,17 @@ type LCDFontPagePtr {.importc: "LCDFontPage*", header: "pd_api.h".} = pointer
type LCDFontPageObj = object
resource: LCDFontPagePtr

proc `=destroy`(this: var LCDFontPageObj) = deallocImpl(this.resource)
proc `=destroy`(this: var LCDFontPageObj) =
discard pdrealloc(this.resource, 0)

type LCDFontPage* = ref LCDFontPageObj

type LCDFontGlyphPtr {.importc: "LCDFontGlyph*", header: "pd_api.h".} = pointer
type LCDFontGlyphObj = object
resource: LCDFontGlyphPtr

proc `=destroy`(this: var LCDFontGlyphObj) = deallocImpl(this.resource)
proc `=destroy`(this: var LCDFontGlyphObj) =
discard pdrealloc(this.resource, 0)

type LCDFontGlyph* = ref LCDFontGlyphObj

Expand Down
10 changes: 10 additions & 0 deletions src/playdate/bindings/initreqs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
##
## Contains direct references to playdate apis that are required to be usable before the
## full API is itself available.
##

var pdrealloc*: proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.}

proc initPrereqs*(realloc: auto) =
## Sets pointers to functions that are needed early in the initialization process
pdrealloc = realloc
63 changes: 29 additions & 34 deletions src/playdate/bindings/malloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,62 +14,57 @@

{.push stackTrace: off.}

# Forward declaration for memory profiling support
when defined(memProfiler):
proc nimProfile(requestedSize: int)
import ../util/initreqs

import memtrace
import system/ansi_c
when defined(memProfiler):

type PDRealloc = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.}
# Forward declaration for memory profiling support
proc nimProfile(requestedSize: int)

proc nativeAlloc(p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} =
if p == nil:
return c_malloc(size)
elif size == 0:
c_free(p)
return nil
else:
return c_realloc(p, size)
template rawAlloc(size): untyped =
# Integrage with: https://nim-lang.org/docs/estp.html
try:
nimProfile(size.int)
except:
discard
pdrealloc(nil, size)

var pdrealloc: PDRealloc
template rawRealloc(p, size): untyped = pdrealloc(p, size)
template rawDealloc(p) = discard pdrealloc(p, 0)

var trace: MemTrace
elif defined(memtrace):
import ../util/memtrace
var trace: MemTrace

template rawAlloc(size): untyped = traceAlloc(trace, pdrealloc, size)
template rawRealloc(p, size): untyped = traceRealloc(trace, pdrealloc, p, size)
template rawDealloc(p) = traceDealloc(trace, pdrealloc, p)

proc setupRealloc*(allocator: PDRealloc) =
when defined(memtrace):
cfprintf(cstderr, "Setting up playdate allocator")
when defined(nativeAlloc):
pdrealloc = nativeAlloc
else:
pdrealloc = allocator
else:
template rawAlloc(size): untyped = pdrealloc(nil, size)
template rawRealloc(p, size): untyped = pdrealloc(p, size)
template rawDealloc(p) = discard pdrealloc(p, 0)

proc allocImpl(size: Natural): pointer =
# Integrage with: https://nim-lang.org/docs/estp.html
when defined(memProfiler):
{.cast(tags: []).}:
try:
nimProfile(size.int)
except:
discard

return trace.alloc(pdrealloc, size.csize_t)
{.cast(tags: []).}:
return rawAlloc(size.csize_t)

proc alloc0Impl(size: Natural): pointer =
result = allocImpl(size)
zeroMem(result, size)

proc reallocImpl(p: pointer, newSize: Natural): pointer =
return trace.realloc(pdrealloc, p, newSize)
{.cast(tags: []).}:
return rawRealloc(p, newSize.csize_t)

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

proc deallocImpl(p: pointer) =
trace.dealloc(pdrealloc, p)
{.cast(tags: []).}:
rawDealloc(p)

# The shared allocators map on the regular ones

Expand Down
3 changes: 2 additions & 1 deletion src/playdate/types.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import util/initreqs

type SDKArrayObj[T] = object
len: int
Expand All @@ -6,7 +7,7 @@ type SDKArray*[T] = ref SDKArrayObj[T]

proc `=destroy`*[T](this: var SDKArrayObj[T]) =
if this.data != nil:
deallocImpl(this.data)
discard pdrealloc(this.data, 0)

proc `[]`*[T](this: SDKArray[T]; i: Natural): lent T =
assert i < this.len
Expand Down
21 changes: 21 additions & 0 deletions src/playdate/util/initreqs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
##
## Contains direct references to playdate apis that are required to be usable before the
## full API is itself available.
##
## This file gets used _very_ early in the Nim initialization process. That means it gets
## imported and used before most of the Nim stdlib is available, so it needs to be almost
## completely self contained.
##

type
PDRealloc* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.}
PDLog* = proc (fmt: cstring) {.cdecl, varargs, raises: [].}

var pdrealloc*: PDRealloc
var pdlog*: PDLog

proc initPrereqs*(realloc: PDRealloc, log: PDLog) =
## Sets pointers to functions from the playdate stdlib that are needed to initialize Nim integrations
log("Initializing Nim playdate globals")
pdrealloc = realloc
pdlog = log
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import system/ansi_c, ../util/sparsemap
import system/ansi_c, sparsemap, initreqs

proc mprotect(a1: pointer, a2: int, a3: cint): cint {.importc, header: "<sys/mman.h>".}

Expand All @@ -13,8 +13,6 @@ const STACK_SIZE = 12
const BUFFER = sizeof(byte) * 8

type
Allocator* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.}

StackString[N : static int] = object
data: array[N, char]
len: int32
Expand Down Expand Up @@ -210,7 +208,7 @@ proc record[N: static int](stack: array[N, StackFrame] = createStackFrame[N](get
discard c_fwrite(addr stack[i].procname, 1, stack[i].procname.len.csize_t, handle)
c_fputc('\n', handle)

proc traceAlloc(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} =
proc traceAlloc*(trace: var MemTrace, alloc: PDRealloc, size: Natural): pointer {.inline.} =
trace.totalAllocs += 1
trace.check

Expand All @@ -231,11 +229,8 @@ proc traceAlloc(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {

trace.allocs[realPointer.ord] = entry

proc alloc*(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} =
proc traceRealloc*(trace: var MemTrace, alloc: PDRealloc, p: pointer, newSize: Natural): pointer {.inline.} =
record[5]()
when defined(memtrace): return traceAlloc(trace, alloc, size) else: return alloc(nil, size.csize_t)

proc traceRealloc(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} =
trace.check

let realInPointer = p.input
Expand Down Expand Up @@ -263,10 +258,7 @@ proc traceRealloc(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Na

trace.allocs[realOutPointer.ord] = entry

proc realloc*(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} =
when defined(memtrace): return traceRealloc(trace, alloc, p, newSize) else: return alloc(p, newSize.csize_t)

proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} =
proc traceDealloc*(trace: var MemTrace, alloc: PDRealloc, p: pointer) {.inline.} =
trace.check
let realPointer = p.input
if realPointer.ord notin trace.allocs:
Expand All @@ -285,6 +277,3 @@ proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.}
discard alloc(realPointer, 0)
trace.deleted[realPointer.ord] = local
trace.allocs.delete(realPointer.ord)

proc dealloc*(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} =
when defined(memtrace): traceDealloc(trace, alloc, p) else: discard alloc(p, 0)
Loading