Minres / SystemC-Components

A SystemC productivity library: https://minres.github.io/SystemC-Components/
https://www.minres.com/#opensource
Apache License 2.0
81 stars 21 forks source link

Memory management potential issue #39

Closed mslijepc closed 1 year ago

mslijepc commented 1 year ago

Hi Eyck,

I haven't seen pool_allocator destructor called. I do see e.g. tlm_mm one called at the end of simulation, and I wander when/how is pool_allocator destructor supposed to be called?

I guess that this should be the case "The storage for the object is allocated when the thread begins and deallocated when the thread ends" cpp reference. Maybe I was doing something wrong?

Would instead of https://github.com/Minres/SystemC-Components/blob/8785c03bd893776668e78a696876c28a14ba6640/src/common/util/pool_allocator.h#L91

something like this be used?

    static pool_allocator<T, CHUNK_SIZE> inst;
eyck commented 1 year ago

Without knowing the used environment and tools, it's hard to comment. In our and our customers environments the destructor of pool_allocator gets called properly and reports about lost memory entries. In principle a static inst could be used but in multi-threaded environments (like our RAVEN product) this requires then the use of mutexes. When running TLM based AT models allocating and freeing the payload happens quite often so this has then some performance impact...

mslijepc commented 1 year ago

When you say multi-threaded, you mean multiple SC_THREADs or pthreads? Or something third?

eyck commented 1 year ago

SC_THREAD is not multi-threaded. By use of quick threads it is a kind of coroutine. I mean multiple parallel SystemC kernels in separate OS threads.

mslijepc commented 1 year ago

Ok, I was using only multiple SC_THREAD. In our setup we are using 3 axi::pin::axi4_target objects, and in total 6 SC_THREADs are calling tlm::scc::tlm_mm<>::get().allocate<axi::axi4_extension>(len) which then calls constructor of memory_pool.

I have 2 questions:

In case (in pool_allocator<T, CHUNK_SIZE>::get()) we use 1) thread_local pool_allocator inst for most of the constructed memory_pool objects (11 out of 16) destructor is not called. What is the lifetime of SC_THREAD? when/how destructor of thread_local variable should be called? In tlm_mm we keep only the reference to created pool_allocator object.

2) static pool_allocator<T, CHUNK_SIZE> inst all destructors are being called. And I think it is safe to use this? No additional mutex are needed?

eyck commented 1 year ago

Ok, I was using only multiple SC_THREAD

SC_THREAD do not interfere at all with OS threads. So it doesn't matter how many of them you are using.

  1. thread_local pool_allocator inst for most of the constructed memory_pool objects (11 out of 16) destructor is not called. What is the lifetime of SC_THREAD? when/how destructor of thread_local variable should be called? In tlm_mm we keep only the reference to created pool_allocator object.

The lifetime of a SC_THREAD does not play any role here as it is just a co-routine being executed in the same OS thread as the simulation kernel. The destructor of the memory manager is being called when the threads is finished. In case of Accellera SystemC this happens when the program stops i.e. sc_main has finished. You can check https://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration

In that the behavior is similar to static life time.

  1. static pool_allocator<T, CHUNK_SIZE> inst all destructors are being called. And I think it is safe to use this? No additional mutex are needed?

In case of plain Accellera SystemC this is correct. For other simulators this does not necessarily hold true.

My guess is that destruction of your design you have a segementation fault or similar which leads to a call to abort(). Abort stops the programm immediately thus skipping any destructors. Under Linux the kernel then frees the used resources (memory, file handles, etc.) automatically.

mslijepc commented 1 year ago

Thank you for the detailed answer. I will double check all the other destructors.