Skip to content

Commit 991ec1f

Browse files
committed
builtin: add -prealloc -d prealloc_memset -d prealloc_memset_value=65 -d prealloc_dump, to better analyze the memory patterns of running V programs
1 parent b0d2eee commit 991ec1f

File tree

2 files changed

+97
-12
lines changed

2 files changed

+97
-12
lines changed

vlib/builtin/cfns.c.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ fn C.fclose(stream &C.FILE) int
8080

8181
fn C.pclose(stream &C.FILE) int
8282

83+
fn C.open(path &char, flags int, mode ...int) int
84+
fn C.close(fd int) int
85+
8386
fn C.strrchr(s &char, c int) &char
8487
fn C.strchr(s &char, c int) &char
8588

vlib/builtin/prealloc.c.v

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,49 @@ __global g_memory_block &VMemoryBlock
2121
struct VMemoryBlock {
2222
mut:
2323
id int
24+
mallocs int
2425
cap isize
25-
start &u8 = 0
26-
previous &VMemoryBlock = 0
2726
remaining isize
28-
current &u8 = 0
29-
mallocs int
27+
previous &VMemoryBlock = 0
28+
next &VMemoryBlock = 0
29+
start &u8 = 0
30+
current &u8 = 0
31+
}
32+
33+
fn vmemory_abort_on_nil(p voidptr, bytes isize) {
34+
if unsafe { p == 0 } {
35+
C.fprintf(C.stderr, c'could not allocate %lld bytes\n', bytes)
36+
exit(1)
37+
}
3038
}
3139

3240
@[unsafe]
3341
fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock {
34-
mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) }
42+
vmem_block_size := sizeof(VMemoryBlock)
43+
mut v := unsafe { &VMemoryBlock(C.calloc(1, vmem_block_size)) }
44+
vmemory_abort_on_nil(v, vmem_block_size)
3545
if unsafe { prev != 0 } {
3646
v.id = prev.id + 1
3747
}
3848

3949
v.previous = prev
40-
block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least }
50+
if unsafe { prev != 0 } {
51+
prev.next = v
52+
}
53+
block_size := if at_least < isize(prealloc_block_size) {
54+
isize(prealloc_block_size)
55+
} else {
56+
at_least
57+
}
58+
$if prealloc_trace_malloc ? {
59+
C.fprintf(C.stderr, c'vmemory_block_new id: %d, block_size: %lld, at_least: %lld\n',
60+
v.id, block_size, at_least)
61+
}
4162
v.start = unsafe { C.malloc(block_size) }
63+
vmemory_abort_on_nil(v.start, block_size)
64+
$if prealloc_memset ? {
65+
unsafe { C.memset(v.start, int($d('prealloc_memset_value', 0)), block_size) }
66+
}
4267
v.cap = block_size
4368
v.remaining = block_size
4469
v.current = v.start
@@ -47,15 +72,19 @@ fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock {
4772

4873
@[unsafe]
4974
fn vmemory_block_malloc(n isize) &u8 {
75+
$if prealloc_trace_malloc ? {
76+
C.fprintf(C.stderr, c'vmemory_block_malloc g_memory_block.id: %d, n: %lld\n',
77+
g_memory_block.id, n)
78+
}
5079
unsafe {
51-
if g_memory_block.remaining < n {
80+
if _unlikely_(g_memory_block.remaining < n) {
5281
g_memory_block = vmemory_block_new(g_memory_block, n)
5382
}
54-
mut res := &u8(0)
83+
mut res := &u8(nil)
5584
res = g_memory_block.current
85+
g_memory_block.current += n
5686
g_memory_block.remaining -= n
5787
g_memory_block.mallocs++
58-
g_memory_block.current += n
5988
return res
6089
}
6190
}
@@ -64,26 +93,79 @@ fn vmemory_block_malloc(n isize) &u8 {
6493

6594
@[unsafe]
6695
fn prealloc_vinit() {
96+
$if prealloc_trace_vinit ? {
97+
C.fprintf(C.stderr, c'prealloc_vinit started\n')
98+
}
6799
unsafe {
68-
g_memory_block = vmemory_block_new(nil, prealloc_block_size)
100+
g_memory_block = vmemory_block_new(nil, isize(prealloc_block_size))
69101
at_exit(prealloc_vcleanup) or {}
70102
}
71103
}
72104

73105
@[unsafe]
74106
fn prealloc_vcleanup() {
107+
$if prealloc_trace_vcleanup ? {
108+
C.fprintf(C.stderr, c'prealloc_vcleanup started\n')
109+
}
75110
$if prealloc_stats ? {
76111
// Note: we do 2 loops here, because string interpolation
77112
// in the first loop may still use g_memory_block
78113
// The second loop however should *not* allocate at all.
79114
mut nr_mallocs := i64(0)
115+
mut total_used := u64(0)
80116
mut mb := g_memory_block
81117
for unsafe { mb != 0 } {
82118
nr_mallocs += mb.mallocs
83-
eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: ${mb.mallocs}')
119+
used := u64(mb.current) - u64(mb.start)
120+
total_used += used
121+
C.fprintf(C.stderr, c'> freeing mb: %16p, mb.id: %3d | cap: %10lld | rem: %10lld | start: %16p | current: %16p | used: %10lld bytes | mallocs: %6d\n',
122+
mb, mb.id, mb.cap, mb.remaining, mb.start, mb.current, used, mb.mallocs)
84123
mb = mb.previous
85124
}
86-
eprintln('> nr_mallocs: ${nr_mallocs}')
125+
C.fprintf(C.stderr, c'> nr_mallocs: %lld, total_used: %lld bytes\n', nr_mallocs,
126+
total_used)
127+
}
128+
$if prealloc_dump ? {
129+
C.fprintf(C.stderr, c'prealloc_vcleanup dumping memory contents ...\n')
130+
mut start := g_memory_block
131+
unsafe {
132+
for start.previous != 0 {
133+
start = start.previous
134+
}
135+
C.fprintf(C.stderr, c'prealloc_vcleanup start: %p\n', start)
136+
C.fprintf(C.stderr, c'prealloc_vcleanup start.id: %d\n', start.id)
137+
C.fprintf(C.stderr, c'prealloc_vcleanup start.next: %p\n', start.next)
138+
139+
mut total_used := u64(0)
140+
path := $d('memdumpfile', 'memdump.bin')
141+
C.fprintf(C.stderr, c'prealloc_vcleanup dumping process memory to path: %s\n',
142+
path.str)
143+
stream := C.fopen(path.str, 'wb'.str)
144+
mut mb := start
145+
for {
146+
used := u64(mb.current) - u64(mb.start)
147+
total_used += used
148+
C.fprintf(C.stderr, c'prealloc_vcleanup dumping mb: %p, mb.id: %d, used: %10lld bytes\n',
149+
mb, mb.id, used)
150+
151+
mut ptr := mb.start
152+
mut remaining_bytes := isize(used)
153+
mut x := isize(0)
154+
for remaining_bytes > 0 {
155+
x = isize(C.fwrite(ptr, 1, remaining_bytes, stream))
156+
ptr += x
157+
remaining_bytes -= x
158+
}
159+
160+
if mb.next == 0 {
161+
break
162+
}
163+
mb = mb.next
164+
}
165+
C.fclose(stream)
166+
C.fprintf(C.stderr, c'prealloc_vcleanup total dump size in bytes: %lld\n',
167+
total_used)
168+
}
87169
}
88170
unsafe {
89171
for g_memory_block != 0 {

0 commit comments

Comments
 (0)