Bug 409606 - Track memory allocated with mmap
Summary: Track memory allocated with mmap
Status: CONFIRMED
Alias: None
Product: Heaptrack
Classification: Applications
Component: general (show other bugs)
Version: unspecified
Platform: Other Linux
: NOR wishlist
Target Milestone: ---
Assignee: Milian Wolff
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-07-08 06:22 UTC by tblodt
Modified: 2021-05-04 18:30 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description tblodt 2019-07-08 06:22:27 UTC
heaptrack currently only tracks memory allocated with malloc, and my program allocates (and leaks) the vast majority of its memory with mmap. It would be nice if mmap-allocated memory could be tracked as well.
Comment 1 Milian Wolff 2019-07-16 20:06:17 UTC
syscalls like mmap cannot be easily intercepted with LD_PRELOAD or similar, which makes it quasi impossible to do with the current architecture of heaptrack.

thankfully, you can easily use perf to achieve the same, since mmap calls are usually done way less often than malloc calls!

    perf record --call-graph dwarf -e syscalls:sys_enter_mmap -- <your app>

interpreting the data may require some more work, but it should be relatively easy I believe based on `perf script` textual output or even a python script.

That said: A convert from such mmap output to the heaptrack data format would be nice, such that we can use the heaptrack GUI to investigate mmap usage.

Also: if anyone knows how to intercept mmap (ptrace?) I'd be all ears :)
Comment 2 tblodt 2019-07-17 04:38:12 UTC
LD_PRELOAD would work at least in my case, since I call mmap through the C library. For times when this doesn't work, intercepting mmap with ptrace is possible, and not all that hard.
Comment 3 Milian Wolff 2019-10-13 20:02:00 UTC
but the mmap symbol in libc is just a shim that gets replaced by a symbol from the vdso, no? and afaik you cannot intercept these via LD_PRELOAD - or am I mistaken?
Comment 4 tblodt 2019-10-13 20:03:44 UTC
There's no mmap symbol in the VDSO. mmap in libc is a wrapper that makes a syscall through the VDSO or directly on some architectures, so you can intercept it.
Comment 5 Milian Wolff 2019-10-13 20:42:48 UTC
Hm yes indeed, I just tested it and I can really intercept it - awesome! I'll definitely want to add that in the future then. I'm not yet sure how to do this properly though, as intercepting mmap may still need some special handling, otherwise it's too easy to deadlock, cf.:

```
(gdb) bt
#0  0x00007f98519df41f in __lll_lock_wait () from /usr/lib/libpthread.so.0
#1  0x00007f98519d7ea3 in pthread_mutex_lock () from /usr/lib/libpthread.so.0
#2  0x00007f9851c16b21 in __gthread_mutex_lock (__mutex=0x7f9851c1c740 <(anonymous namespace)::HeapTrack::s_lock>)
    at /usr/include/c++/9.2.0/x86_64-pc-linux-gnu/bits/gthr-default.h:749
#3  std::mutex::lock (this=0x7f9851c1c740 <(anonymous namespace)::HeapTrack::s_lock>) at /usr/include/c++/9.2.0/bits/std_mutex.h:100
#4  (anonymous namespace)::HeapTrack::HeapTrack (this=<synthetic pointer>) at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:235
#5  heaptrack_init (outputFileName=0x0, 
    initBeforeCallback=initBeforeCallback@entry=0x7f9851c14000 <(anonymous namespace)::hooks::<lambda()>::_FUN(void)>, 
    initAfterCallback=initAfterCallback@entry=0x0, stopCallback=stopCallback@entry=0x0)
    at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:689
#6  0x00007f9851c13f77 in (anonymous namespace)::hooks::init () at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:147
#7  0x00007f9851c145d5 in mmap (addr=addr@entry=0x0, length=length@entry=4096, prot=prot@entry=3, flags=flags@entry=34, fd=fd@entry=-1, 
    offset=offset@entry=0) at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:336
#8  0x00007f98519aca5a in expand (pool=pool@entry=0x7f98519cbb60 <dwarf_reg_state_pool>)
    at /home/milian/projects/src/libunwind/src/mi/mempool.c:111
#9  0x00007f98519acbd6 in _UIx86_64__mempool_init (pool=pool@entry=0x7f98519cbb60 <dwarf_reg_state_pool>, obj_size=obj_size@entry=192, 
    reserve=<optimized out>, reserve@entry=0) at /home/milian/projects/src/libunwind/src/mi/mempool.c:150
#10 0x00007f98519b9617 in _Ux86_64_dwarf_init () at /home/milian/projects/src/libunwind/src/dwarf/global.c:34
#11 0x00007f98519adbf8 in _ULx86_64_init () at /home/milian/projects/src/libunwind/src/x86_64/Gglobal.c:91
#12 0x00007f98519ad96a in _ULx86_64_set_caching_policy (as=0x7f98519c5340 <local_addr_space>, policy=policy@entry=UNW_CACHE_PER_THREAD)
    at /home/milian/projects/src/libunwind/src/mi/Gset_caching_policy.c:32
#13 0x00007f9851c14755 in (anonymous namespace)::HeapTrack::<lambda()>::operator() (__closure=<optimized out>)
    at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:265
#14 std::__invoke_impl<void, (anonymous namespace)::HeapTrack::initialize(char const*, heaptrack_callback_t, heaptrack_callback_initialized_t, heaptrack_callback_t)::<lambda()> > (__f=...) at /usr/include/c++/9.2.0/bits/invoke.h:60
#15 std::__invoke<(anonymous namespace)::HeapTrack::initialize(char const*, heaptrack_callback_t, heaptrack_callback_initialized_t, heaptrack_cal--Type <RET> for more, q to quit, c to continue without paging--
lback_t)::<lambda()> > (__fn=...) at /usr/include/c++/9.2.0/bits/invoke.h:95
#16 std::<lambda()>::operator() (this=<optimized out>) at /usr/include/c++/9.2.0/mutex:671
#17 std::<lambda()>::operator() (this=0x0) at /usr/include/c++/9.2.0/mutex:676
#18 std::<lambda()>::_FUN(void) () at /usr/include/c++/9.2.0/mutex:676
#19 0x00007f98519dd87f in __pthread_once_slow () from /usr/lib/libpthread.so.0
#20 0x00007f9851c16beb in __gthread_once (__func=<optimized out>, 
    __once=0x7f9851c1c768 <(anonymous namespace)::HeapTrack::initialize(char const*, void (*)(), void (*)(LineWriter&), void (*)())::once>)
    at /usr/include/c++/9.2.0/x86_64-pc-linux-gnu/bits/gthr-default.h:700
#21 std::call_once<(anonymous namespace)::HeapTrack::initialize(char const*, heaptrack_callback_t, heaptrack_callback_initialized_t, heaptrack_callback_t)::<lambda()> > (__once=..., __f=...) at /usr/include/c++/9.2.0/mutex:683
#22 (anonymous namespace)::HeapTrack::initialize (this=<synthetic pointer>, stopCallback=0x0, initAfterCallback=0x0, 
    initBeforeCallback=0x7f9851c14000 <(anonymous namespace)::hooks::<lambda()>::_FUN(void)>, 
    fileName=0x7ffd605db4be "/tmp/heaptrack_fifo824597") at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:262
#23 heaptrack_init (outputFileName=0x7ffd605db4be "/tmp/heaptrack_fifo824597", 
    initBeforeCallback=initBeforeCallback@entry=0x7f9851c14000 <(anonymous namespace)::hooks::<lambda()>::_FUN(void)>, 
    initAfterCallback=initAfterCallback@entry=0x0, stopCallback=stopCallback@entry=0x0)
    at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:690
#24 0x00007f9851c13f77 in (anonymous namespace)::hooks::init () at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:147
#25 0x00007f9851c142ed in malloc (size=size@entry=72704) at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:181
#26 0x00007f9851852c8b in (anonymous namespace)::pool::pool (this=0x7f9851999240 <(anonymous namespace)::emergency_pool>)
    at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:123
#27 __static_initialization_and_destruction_0 (__priority=65535, __initialize_p=1) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:262
#28 _GLOBAL__sub_I_eh_alloc.cc(void) () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:338
#29 0x00007f9851c2f72a in call_init.part () from /lib64/ld-linux-x86-64.so.2
#30 0x00007f9851c2f831 in _dl_init () from /lib64/ld-linux-x86-64.so.2
#31 0x00007f9851c2113a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
--Type <RET> for more, q to quit, c to continue without paging--
#32 0x0000000000000001 in ?? ()
#33 0x00007ffd605db4a5 in ?? ()
#34 0x0000000000000000 in ?? ()
```

but I'm sure one can find a way to resolve this.
Comment 6 Milian Wolff 2019-10-13 21:08:45 UTC
nvm that, I forgot to init the mmap hook, it all seems to work fine actually! thanks a lot for bringing this to my attention, I'm seriously wondering why I never tried this out so far.
Comment 7 Pash 2021-02-19 05:07:46 UTC
Look to Samsung/tizen's heaptrack. It has fixes for logging of mmap. But not only mmap. Sorry.
Comment 8 Milian Wolff 2021-02-19 09:09:30 UTC
@Pash: do you mean samsung/tizen has forked heaptrack? cool! can you refer me to their code repo? First time I hear about that.
Comment 9 Milian Wolff 2021-02-19 09:28:12 UTC
found it: https://git.tizen.org/cgit/sdk/tools/heaptrack/

quite sad that they never ever spoke to me, nor even tried to upstream some of their changes :(
Comment 10 Pash 2021-02-24 13:34:53 UTC
(In reply to Milian Wolff from comment #9)
> found it: https://git.tizen.org/cgit/sdk/tools/heaptrack/
> 
> quite sad that they never ever spoke to me, nor even tried to upstream some
> of their changes :(

I am trying :)  but 5 day w/o any live: https://invent.kde.org/sdk/heaptrack/-/merge_requests/4

Where I am wrong?
Comment 11 Andrew Somerville 2021-04-30 22:50:21 UTC
What would it take to merge in the mmap features from the tizen fork? I might be willing to so some work to make it happen.
Comment 12 Andrew Somerville 2021-05-04 18:30:56 UTC
I created https://github.com/catskul/tizen-heaptrack to make comparison, PRs, and forking easier. I'll take a look later to see if there's any twidling I need to do to make it share history with https://github.com/KDE/heaptrack