first version of the new memory tracking feature
This commit is contained in:
parent
fa101a722f
commit
02a2180a6a
11 changed files with 167 additions and 4 deletions
71
lib/pure/nimtracker.nim
Normal file
71
lib/pure/nimtracker.nim
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2016 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Memory tracking support for Nim.
|
||||
|
||||
when isMainModule:
|
||||
import db_sqlite
|
||||
var db = open("memtrack.db", "", "", "")
|
||||
db.exec sql"""
|
||||
create table if not exists Tracking(
|
||||
id integer primary key,
|
||||
op varchar not null,
|
||||
address integer not null,
|
||||
size integer not null,
|
||||
file varchar not null,
|
||||
line integer not null
|
||||
)"""
|
||||
db.close()
|
||||
else:
|
||||
when not defined(memTracker):
|
||||
{.error: "Memory tracking support is turned off!".}
|
||||
|
||||
{.push memtracker: off.}
|
||||
# we import the low level wrapper and are careful not to use Nim's
|
||||
# memory manager for anything here.
|
||||
import sqlite3
|
||||
|
||||
var
|
||||
dbHandle: PSqlite3
|
||||
insertStmt: Pstmt
|
||||
|
||||
template sbind(x: int; value) =
|
||||
when value is cstring:
|
||||
let ret = insertStmt.bindText(x, value, value.len.int32, SQLITE_TRANSIENT)
|
||||
if ret != SQLITE_OK:
|
||||
quit "could not bind value"
|
||||
else:
|
||||
let ret = insertStmt.bindInt64(x, value)
|
||||
if ret != SQLITE_OK:
|
||||
quit "could not bind value"
|
||||
|
||||
proc logEntries(log: TrackLog) {.nimcall.} =
|
||||
for i in 0..log.count-1:
|
||||
var success = false
|
||||
let e = log.data[i]
|
||||
discard sqlite3.reset(insertStmt)
|
||||
discard clearBindings(insertStmt)
|
||||
sbind 1, e.op
|
||||
sbind(2, cast[int](e.address))
|
||||
sbind 3, e.size
|
||||
sbind 4, e.file
|
||||
sbind 5, e.line
|
||||
if step(insertStmt) == SQLITE_DONE:
|
||||
success = true
|
||||
if not success:
|
||||
quit "could not write to database!"
|
||||
|
||||
if sqlite3.open("memtrack.db", dbHandle) == SQLITE_OK:
|
||||
const query = "INSERT INTO tracking(op, address, size, file, line) values (?, ?, ?, ?, ?)"
|
||||
if prepare_v2(dbHandle, query,
|
||||
query.len, insertStmt, nil) == SQLITE_OK:
|
||||
setTrackLogger logEntries
|
||||
else:
|
||||
quit "could not prepare statement"
|
||||
{.pop.}
|
||||
|
|
@ -1272,12 +1272,14 @@ const
|
|||
|
||||
seqShallowFlag = low(int)
|
||||
|
||||
{.push profiler: off.}
|
||||
when defined(nimKnowsNimvm):
|
||||
let nimvm* {.magic: "Nimvm".}: bool = false
|
||||
## may be used only in "when" expression.
|
||||
## It is true in Nim VM context and false otherwise
|
||||
else:
|
||||
const nimvm*: bool = false
|
||||
{.pop.}
|
||||
|
||||
proc compileOption*(option: string): bool {.
|
||||
magic: "CompileOption", noSideEffect.}
|
||||
|
|
@ -2544,6 +2546,7 @@ when hostOS == "standalone":
|
|||
include "$projectpath/panicoverride"
|
||||
|
||||
when not declared(sysFatal):
|
||||
{.push profiler: off.}
|
||||
when hostOS == "standalone":
|
||||
proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
|
||||
panic(message)
|
||||
|
|
@ -2563,6 +2566,7 @@ when not declared(sysFatal):
|
|||
new(e)
|
||||
e.msg = message & arg
|
||||
raise e
|
||||
{.pop.}
|
||||
|
||||
proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
|
||||
## get type information for `x`. Ordinary code should not use this, but
|
||||
|
|
@ -2616,8 +2620,10 @@ when not defined(JS): #and not defined(nimscript):
|
|||
when declared(setStackBottom):
|
||||
setStackBottom(locals)
|
||||
|
||||
{.push profiler: off.}
|
||||
var
|
||||
strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic})
|
||||
{.pop.}
|
||||
|
||||
|
||||
# ----------------- IO Part ------------------------------------------------
|
||||
|
|
@ -2950,6 +2956,8 @@ when not defined(JS): #and not defined(nimscript):
|
|||
## lead to the ``raise`` statement. This only works for debug builds.
|
||||
|
||||
{.push stack_trace: off, profiler:off.}
|
||||
when defined(memtracker):
|
||||
include "system/memtracker"
|
||||
when hostOS == "standalone":
|
||||
include "system/embedded"
|
||||
else:
|
||||
|
|
@ -2992,7 +3000,9 @@ when not defined(JS): #and not defined(nimscript):
|
|||
else:
|
||||
result = n.sons[n.len]
|
||||
|
||||
{.push profiler:off.}
|
||||
when hasAlloc: include "system/mmdisp"
|
||||
{.pop.}
|
||||
{.push stack_trace: off, profiler:off.}
|
||||
when hasAlloc: include "system/sysstr"
|
||||
{.pop.}
|
||||
|
|
|
|||
|
|
@ -339,6 +339,8 @@ when not defined(noSignalHandler):
|
|||
action("unknown signal\n")
|
||||
|
||||
# print stack trace and quit
|
||||
when defined(memtracker):
|
||||
logPendingOps()
|
||||
when hasSomeStackTrace:
|
||||
GC_disable()
|
||||
var buf = newStringOfCap(2000)
|
||||
|
|
|
|||
62
lib/system/memtracker.nim
Normal file
62
lib/system/memtracker.nim
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2016 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Memory tracking support for Nim.
|
||||
|
||||
when not defined(memTracker):
|
||||
{.error: "Memory tracking support is turned off! Enable memory tracking by passing `--memtracker:on` to the compiler (see the Nim Compiler User Guide for more options).".}
|
||||
|
||||
when defined(noSignalHandler):
|
||||
{.error: "Memory tracking works better with the default signal handler.".}
|
||||
|
||||
# We don't want to memtrack the tracking code ...
|
||||
{.push memtracker: off.}
|
||||
|
||||
type
|
||||
LogEntry* = object
|
||||
op*: cstring
|
||||
address*: pointer
|
||||
size*: int
|
||||
file*: cstring
|
||||
line*: int
|
||||
TrackLog* = object
|
||||
count*: int
|
||||
data*: array[4000, LogEntry]
|
||||
TrackLogger* = proc (log: TrackLog) {.nimcall.}
|
||||
|
||||
var
|
||||
gLog*: TrackLog
|
||||
gLogger*: TrackLogger = proc (log: TrackLog) = discard
|
||||
|
||||
proc setTrackLogger*(logger: TrackLogger) =
|
||||
gLogger = logger
|
||||
|
||||
proc addEntry(entry: LogEntry) =
|
||||
if gLog.count > high(gLog.data):
|
||||
gLogger(gLog)
|
||||
gLog.count = 0
|
||||
gLog.data[gLog.count] = entry
|
||||
inc gLog.count
|
||||
|
||||
proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.compilerProc.} =
|
||||
addEntry LogEntry(op: "write", address: address,
|
||||
size: size, file: file, line: line)
|
||||
|
||||
proc memTrackerOp*(op: cstring; address: pointer; size: int) =
|
||||
addEntry LogEntry(op: op, address: address, size: size,
|
||||
file: "", line: 0)
|
||||
|
||||
proc logPendingOps() {.noconv.} =
|
||||
# forward declared and called from Nim's signal handler.
|
||||
gLogger(gLog)
|
||||
gLog.count = 0
|
||||
|
||||
addQuitProc logPendingOps
|
||||
|
||||
{.pop.}
|
||||
Loading…
Add table
Add a link
Reference in a new issue