Skip to content

sbrk() allocation tracing in --memoryprofiler has regressed by PR #19174 #21223

@juj

Description

@juj

It looks like the --memoryprofiler feature where it visualizes the callstacks of all callers to the sbrk() function has regressed.

This is a little known feature and very non-tested, though it's saved my bacon a couple of times when debugging low level memory issues at Unity.

The way it is supposed to work is that when --memoryprofiler shows that visual map of the memory:

image

then tapping on that checkbox is intended to cut the visual image into top and bottom parts, where the top part shows allocation/residency as usual, but the bottom part is then supposed to paint blocks of calls to sbrk() grows in distinct colors per callstack.

But now I observe that I am instead getting this

image

i.e. the initial heap is shown in pink, but then subsequent calls to sbrk() are not colored at all. (the graph should show different colored pink blocks extending all the way right from the first pink block)

At Unity I use this to debug the memory sbrk fragmentation caused by native dlmalloc vs Boehm GC malloc regions (for managed C# memory) that both independently sbrk() in memory.

Looking into this, in memoryprofiler.js there is a function emscriptenMemoryProfiler.onSbrkGrow() that is supposed to be called from every sbrk() call, and the implementation of sbrk() does still have the line

emscripten_memprof_sbrk_grow(old_brk, new_brk);

intact.

This line should activate when building with --tracing, which is implied if --memoryprofiler is set. However, I see that when building Unity content with --memoryprofiler, the generated .js file does not receive a call to emscripten_memprof_sbrk_grow() at all, which makes sense only if that function got stubbed out.

Looking at the generated archive files after building with --memoryprofiler, we have

image

where we have a libdlmalloc-tracing.a file, but the issues is that sbrk.c is not built as part of that file, but it is built in libc.a file, which gets built without the --tracing flag. So the call to emscripten_memprof_sbrk_grow() always gets stubbed out by this:

#ifdef __EMSCRIPTEN_TRACING__
void emscripten_memprof_sbrk_grow(intptr_t old, intptr_t new);
#else
#define emscripten_memprof_sbrk_grow(...) ((void)0)
#endif

i.e. that file is never built by system_libs.py with __EMSCRIPTEN_TRACING__ set.

Looking at history, it seems like PR #19174 refactored sbrk.c out from libdlmalloc-tracing.a into libc.a, which seems to have caused this regression.

I wonder if the simplest fix might be to locate it back in? We probably don't want to add a -tracing variant of the whole libc.a file, as that would cause a lot of redundant duplication?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions