Skip to content

Commit 66afd2f

Browse files
DO NOT MERGE - Cherrypick from original heaptrack_support branch for Nim v2.0.12
1 parent ce7c6f4 commit 66afd2f

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

lib/system/alloc.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,15 @@ when defined(gcDestructors):
861861
dec maxIters
862862
if it == nil: break
863863

864+
when defined(heaptracker):
865+
const heaptrackLib =
866+
when defined(heaptracker_inject):
867+
"libheaptrack_inject.so"
868+
else:
869+
"libheaptrack_preload.so"
870+
proc heaptrack_malloc(a: pointer, size: int) {.cdecl, importc, dynlib:heaptrackLib.}
871+
proc heaptrack_free(a: pointer) {.cdecl, importc, dynlib:heaptrackLib.}
872+
864873
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
865874
when defined(nimTypeNames):
866875
inc(a.allocCounter)
@@ -983,6 +992,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
983992
sysAssert(isAccessible(a, result), "rawAlloc 14")
984993
sysAssert(allocInv(a), "rawAlloc: end")
985994
when logAlloc: cprintf("var pointer_%p = alloc(%ld) # %p\n", result, requestedSize, addr a)
995+
when defined(heaptracker): heaptrack_malloc(result, requestedSize)
986996

987997
proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
988998
result = rawAlloc(a, requestedSize)
@@ -991,6 +1001,8 @@ proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
9911001
proc rawDealloc(a: var MemRegion, p: pointer) =
9921002
when defined(nimTypeNames):
9931003
inc(a.deallocCounter)
1004+
when defined(heaptracker):
1005+
heaptrack_free(p)
9941006
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
9951007
sysAssert(allocInv(a), "rawDealloc: begin")
9961008
var c = pageAddr(p)

readme.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,70 @@
11
# <img src="https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png" height="28px"/> Nim
22

3+
## Notice for this special version -> v2.0.12 with Heaptrack support
4+
# Heaptrack for Nim
5+
6+
This branch allows you to use [heaptrack](https://github.com/KDE/heaptrack) on nim programs.
7+
8+
## Heaptrack
9+
Heaptrack is a neat little tool used for RAM usage debugging, allowing to find leaks, allocation hotspots, etc.
10+
11+
It's usable in two ways:
12+
- Preload: ex, `heaptrack ls`, will preload `libheaptrack_preload.so` into ls, and record every allocation during the entire program
13+
- Inject: ex, `ls &; heaptrack -p $(pidof ls)`, will attach to the running program using `gdb`, inject `libheaptrack_inject.so`, and record every allocation from this point until the program finishes or `heaptrack` is killed.
14+
15+
Preload is more useful for short-running application, and allow to detect memory leaks as well.
16+
17+
Inject is useful to monitor a precise moment of a long running application, and can't detected memory leaks (since the program could `free` the allocated memory after we've detached, or have `alloc`ated before we attached)
18+
19+
Internally, `heaptrack` works by writing into a file each allocation and dellocation done by the program, along with the stacktrace for each allocation, eg:
20+
21+
```
22+
+ 55c7e2ff17ea 15 #Allocated 21 bytes into address "55c7e2ff17ea"
23+
- 55c7e2ff17ea #Deallocated pointer "55c7e2ff17ea"
24+
```
25+
(note, this is a simplification of the actual format, which is optimized to be machine-readable but not human readable)
26+
27+
For most of programs, it just wraps `malloc` and `free` into custom function to create this file, but obviously, nim doesn't use `malloc` and `free`, so some trickery is required.
28+
29+
## Heaptrack in Nim
30+
This branch simply plugs the `libheaptrack`'s procs into the nim gc, allowing to use heaptrack for nim programs.
31+
```bash
32+
nim c -d:heaptracker test.nim
33+
heaptrack ./test #works as any program
34+
```
35+
36+
Be careful, to use the `inject` mode, the `libheaptrack_inject.so` must be used instead of `libheaptrack_preload.so` during compilation:
37+
```bash
38+
nim c -d:heaptracker -d:heaptracker_inject test.nim
39+
LD_LIBRARY_PATH=/usr/local/lib/heaptrack ./test &
40+
heaptrack -p $(pidof test)
41+
```
42+
The binary must use the same `.so` as `heaptrack`, so an `inject` binary won't work with `prelude`, and a `prelude` binary won't work with `inject`
43+
44+
Be also careful, once a binary has been compiled with `-d:heaptracker`, it won't run on a device where `heaptrack` is not installed.
45+
For `inject`, you also need to specify the `LD_LIBRARY_PATH` to locate the `so` files.
46+
47+
## Heaptrack for Nimbus
48+
To build nimbus with heaptrack enabled:
49+
Add to the Makefile the required flags, as [shown here](https://github.com/status-im/nimbus-eth2/commit/90eca6d54309db669f03866fb8d432b739687f70)
50+
51+
Change to build Dockerfile to add `apt install heaptrack` and set the `LD_LIBRARY_PATH` properly
52+
53+
Add `gdb` capabilities to the docker-compose.yml
54+
```yaml
55+
cap_add:
56+
- 'SYS_PTRACE'
57+
security_opt:
58+
- 'seccomp:unconfined'
59+
```
60+
61+
Once everything is setup, you can go into the container, install gdb, and run `heaptrack -p 1` as usual.
62+
When you're happy with your capture, stop heaptrack, retrieve the file on your computer for analysis, and voilà!
63+
64+
65+
66+
67+
368
[![Build Status](https://dev.azure.com/nim-lang/Nim/_apis/build/status/nim-lang.Nim?branchName=devel)](https://dev.azure.com/nim-lang/Nim/_build/latest?definitionId=1&branchName=devel)
469

570
This repository contains the Nim compiler, Nim's stdlib, tools, and documentation.

0 commit comments

Comments
 (0)