memtracker.nim 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2016 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Memory tracking support for Nim.
  10. when not defined(memTracker):
  11. {.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).".}
  12. when defined(noSignalHandler):
  13. {.error: "Memory tracking works better with the default signal handler.".}
  14. # We don't want to memtrack the tracking code ...
  15. {.push memtracker: off.}
  16. when declared(getThreadId):
  17. template myThreadId(): untyped = getThreadId()
  18. else:
  19. template myThreadId(): untyped = 0
  20. type
  21. LogEntry* = object
  22. op*: cstring
  23. address*: pointer
  24. size*: int
  25. file*: cstring
  26. line*: int
  27. thread*: int
  28. TrackLog* = object
  29. count*: int
  30. disabled: bool
  31. data*: array[400, LogEntry]
  32. TrackLogger* = proc (log: TrackLog) {.nimcall, tags: [], gcsafe.}
  33. var
  34. gLog*: TrackLog
  35. gLogger*: TrackLogger = proc (log: TrackLog) = discard
  36. ilocs: array[4000, (int, int)]
  37. ilocn: int
  38. proc trackLocation*(p: pointer; size: int) =
  39. let x = (cast[int](p), size)
  40. for i in 0..ilocn-1:
  41. # already known?
  42. if ilocs[i] == x: return
  43. ilocs[ilocn] = x
  44. inc ilocn
  45. proc setTrackLogger*(logger: TrackLogger) =
  46. gLogger = logger
  47. proc addEntry(entry: LogEntry) =
  48. if not gLog.disabled:
  49. var interesting = false
  50. for i in 0..ilocn-1:
  51. let p = ilocs[i]
  52. # X..Y and C..D overlap iff (X <= D and C <= Y)
  53. let x = p[0]
  54. let y = p[0]+p[1]-1
  55. let c = cast[int](entry.address)
  56. let d = c + entry.size-1
  57. if x <= d and c <= y:
  58. interesting = myThreadId() != entry.thread # true
  59. break
  60. if interesting:
  61. gLog.disabled = true
  62. cprintf("interesting %s:%ld %s\n", entry.file, entry.line, entry.op)
  63. let x = cast[proc() {.nimcall, tags: [], gcsafe, raises: [].}](writeStackTrace)
  64. x()
  65. quit 1
  66. #if gLog.count > high(gLog.data):
  67. # gLogger(gLog)
  68. # gLog.count = 0
  69. #gLog.data[gLog.count] = entry
  70. #inc gLog.count
  71. #gLog.disabled = false
  72. proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.compilerproc.} =
  73. addEntry LogEntry(op: "write", address: address,
  74. size: size, file: file, line: line, thread: myThreadId())
  75. proc memTrackerOp*(op: cstring; address: pointer; size: int) {.tags: [],
  76. gcsafe.} =
  77. addEntry LogEntry(op: op, address: address, size: size,
  78. file: "", line: 0, thread: myThreadId())
  79. proc memTrackerDisable*() =
  80. gLog.disabled = true
  81. proc memTrackerEnable*() =
  82. gLog.disabled = false
  83. proc logPendingOps() {.noconv.} =
  84. # forward declared and called from Nim's signal handler.
  85. gLogger(gLog)
  86. gLog.count = 0
  87. import std/exitprocs
  88. addExitProc logPendingOps
  89. {.pop.}