Skip to content

More verbose -print-allocs messages. Initial commit.#5504

Draft
ebak wants to merge 4 commits into
tinygo-org:devfrom
ebak:print-allocs-verbose
Draft

More verbose -print-allocs messages. Initial commit.#5504
ebak wants to merge 4 commits into
tinygo-org:devfrom
ebak:print-allocs-verbose

Conversation

@ebak

@ebak ebak commented Jul 6, 2026

Copy link
Copy Markdown

This change intends to provide more verbose -print-allocs messages by naming the escaping intermediate variable or type.
Currently it is tested only with the unit tests.

Here are the modified messages, generated by allocs_test.go:

makeslice.buf size is not constant
makeslice4 size 300 exceeds maximum stack allocation size 256
makeslice6 escapes at line 30
FloatType escapes at line 37
varargs12 escapes at line 44
slicelit14 escapes at line 47
n4 escapes at line 51
n5 escapes at line 51
makeslice escapes at line 108
b escapes at line 117
Arg 0 of main.scaleVector3() call escapes at line 122
b escapes at unknown line

@dgryski dgryski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems good but someone else a bit more familiar with this code should take a look.

@ebak
ebak marked this pull request as draft July 10, 2026 08:08
@ebak

ebak commented Jul 12, 2026

Copy link
Copy Markdown
Author

Now the messages from the allocs_test.go unit test are looking like this:

allocs2.go:26: makeslice.buf size is not constant
allocs2.go:28: makeslice4 size 300 exceeds maximum stack allocation size 256
allocs2.go:31: makeslice6 escapes at line 32
allocs2.go:38: Arg 0 (type: basic:complex128) of main.useInterface() escapes at line 40
allocs2.go:43: Arg 0 (type: array:3:basic:int32) of main.useInterface() escapes at line 43
allocs2.go:50: varargs12 escapes at line 50
allocs2.go:52: slicelit14 escapes at line 53
allocs2.go:55: n4 escapes at line 57
allocs2.go:56: n5 escapes at line 57
allocs2.go:132: makeslice escapes at line 133
allocs2.go:139: b escapes at line 142
allocs2.go:148: Arg 0 of main.scaleVector3() escapes at line 149
allocs2.go:150: complit1 escapes at line 151
allocs2.go:150: complit2 escapes at line 151
allocs2.go:156: Arg 1 (type: pointer:named:main.vector3) of main.useInterfaces() escapes at line 156
allocs2.go:156: Arg 4 (type: pointer:named:main.vector3) of main.useInterfaces() escapes at line 156
allocs2.go:160: Arg 1 (type: pointer:named:main.vector3) of main.useInterfaces() escapes at line 160
allocs2.go:160: Arg 4 (type: pointer:named:main.vector3) of main.useInterfaces() escapes at line 160
allocs2.go:171: b escapes at unknown line
allocs2.go:179: varargs escapes at line 179
allocs2.go:184: main.theError escapes at line 184
allocs2.go:188: main.theError escapes at line 188
allocs2.go:193: array:3:basic:int32 escapes at line 193

I also executed this -print-allocs on one of my projects and I got these results:

heap/storage/unsafe_arraylist.go:64:30: heap allocation: 16 bytes escapes at line 64
heap/checks/string_test.go:35:30: heap allocation: 16 bytes escapes at line 35
heap/checks/string_test.go:13:2: heap allocation: alloc escapes at line 16   // --- here "alloc" is a variable name
heap/checks/string_test.go:10:17: heap allocation: t1 escapes at line 16
heap/checks/string_test.go:48:79: heap allocation: 96 bytes escapes at line 48
heap/checks/string_test.go:45:21: heap allocation: 16 bytes escapes at line 48
heap/checks/str_test.go:24:3: heap allocation: str escapes at line 14
heap/checks/str_test.go:17:2: heap allocation: alloc escapes at line 14      // --- here "alloc" is a variable name
heap/checks/utils.go:16:25: heap allocation: 16 bytes escapes at line 16
heap/internal/holecache/simple/simple.go:22:15: heap allocation: complit escapes at line 22
heap/internal/heap/allocator.go:47:14: heap allocation: makeslice.buf escapes at line 51
heap/internal/heap/allocator.go:235:20: heap allocation: heap/internal/heap.AllocError escapes at line 235
heap/internal/heap/allocator.go:218:20: heap allocation: heap/internal/heap.AllocError escapes at line 218
heap/internal/heap/allocator.go:213:20: heap allocation: heap/internal/heap.AllocError escapes at line 213
heap/internal/heap/allocator.go:179:22: heap allocation: heap/internal/heap.AllocError escapes at line 179
heap/internal/heap/allocator.go:386:20: heap allocation: heap/internal/heap.AllocError escapes at line 386
heap/internal/heap/allocator.go:374:23: heap allocation: heap/internal/heap.AllocError escapes at line 374
heap/internal/heap/allocator.go:311:31: heap allocation: heap/internal/heap.AllocError escapes at line 314
heap/internal/heap/allocator.go:199:29: heap allocation: heap/internal/heap.AllocError escapes at line 182
heap/internal/heap/allocator.go:196:33: heap allocation: heap/internal/heap.AllocError escapes at line 196

Of course it is far from being perfect, but probably there is more possibility for mining out the name and/or type of the escaped object from LLVM IR and this change could be a stub for that.

@ebak
ebak marked this pull request as ready for review July 12, 2026 10:12
Comment thread transform/idminer.go
return
}

func dumpIR(hdr string, instCnt int, fstInst llvm.Value) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems dumpIR is unused?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, anyone who touches this code can use it for debugging.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove test code like this, it leads to clutter.

@aykevl aykevl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree with the idea here, the PR does need some cleanup before merging (lots of debugging code, commented out code, etc).

Also, the values printed here are mostly internal compiler values that I'm afraid will mostly be confusing to users. I recommend instead to look into adding a string attribute to the runtime.alloc call, that can then be retrieved during the printing to get the type (and perhaps the reason why it was allocated, such as "making a slice"). I'd prefer if those internal values would stay internal and we show something actually useful to users. It would be nice to have a message like "[]byte slice allocated at line X" which would be possible this way.

Comment thread transform/idminer.go
return
}

func dumpIR(hdr string, instCnt int, fstInst llvm.Value) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove test code like this, it leads to clutter.

Comment thread transform/testdata/allocs2.go Outdated
theErr := theError{}
var err error = theErr
theErr.set("hello")
println(err.Error())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug code, remove please.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aykevl, thanks for the advise. I made an initial implementation. Unfortunately not all alloc calls get the attributes.
I have found 2 places in compiler/compiler.go, where setting attributes are reflected in LLVM IR alloc calls. These places are in builder.createExpr(expr ssa.Value) in case *ssa.Alloc: and case *ssa.MakeSlice:.
I have also checked where builder.createAlloc() are used, but I haven't identified relevant places.

Now the test output looks like this:

allocs2.go:26: slice size is not constant
allocs2.go:28: slice [300]byte size 300 exceeds maximum stack allocation size 256
allocs2.go:31: slice [4]int escapes at line 32
allocs2.go:38: Arg 0 (type: basic:complex128) of main.useInterface() escapes at line 40      // --- Fallback
allocs2.go:43: Arg 0 (type: array:3:basic:int32) of main.useInterface() escapes at line 43   // --- Fallback
allocs2.go:50: varargs [3]int escapes at line 50
allocs2.go:52: slice [3]int escapes at line 53
allocs2.go:55: n4 escapes at line 57
allocs2.go:56: n5 escapes at line 57
allocs2.go:127: slice [3]int escapes at line 128
allocs2.go:134: b escapes at line 137
allocs2.go:143: main.vector3 escapes at line 144
allocs2.go:145: main.vector3 escapes at line 146
allocs2.go:145: main.vector3 escapes at line 146
allocs2.go:151: main.vector3 escapes at line 151
allocs2.go:151: main.vector3 escapes at line 151
allocs2.go:155: main.vector3 escapes at line 155
allocs2.go:155: main.vector3 escapes at line 155
allocs2.go:166: b escapes at unknown line
allocs2.go:174: varargs [1]any escapes at line 174
allocs2.go:179: main.theError escapes at line 179
allocs2.go:183: main.theError escapes at line 183
allocs2.go:188: array:3:basic:int32 escapes at line 188    // --- Fallback

Do you have idea for improvement?

@ebak
ebak marked this pull request as draft July 13, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants