[Lldb-commits] Performing ManualDWARFIndex::Index() async during ManualDWARFIndex::Preload()

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Sun Jan 31 05:21:34 PST 2021


On 29/01/2021 16:25, Lasse Folger via lldb-commits wrote:
 > Hi lldb devs,
 >
 > We experienced some issues when debugging large binaries.
 > The startup time of lldb for large binaries is long (tens of seconds).
 > One of the reasons is that the /ManualDWARFIndex::Index()/ function is
 > executed synchronously and thus blocks during startup.

Before I go further, let me ask this: You are aware of the 
'target.preload-symbols' setting which can disable (delay) the indexing 
at starting, right? I am asking because it may result in a similar 
behavior than what you get with your patch. At the very least, it would 
be interesting to see a comparison of the two scenarios, to get a feel 
for the benefits it offers.

On 29/01/2021 18:23, Lasse Folger via lldb-commits wrote:
> Thanks Raphael for the pointers, I will take a look.
> 
> I just noticed I forgot to attach the actual patch I prepared ;)
> Here it is.
> 
> On Fri, Jan 29, 2021, 5:02 PM Raphael “Teemperor” Isemann 
> <teemperor at gmail.com <mailto:teemperor at gmail.com>> wrote:
> 
>     I can't help with any of the requested feedback, but the last time I
>     looked at a benchmark involving ManualDWARFIndex, the
>     ManualDWARFIndex::IndexUnit spent about 40% of its runtime just
>     constructing ConstString. Half of that 40% (so, 20% total time) was
>     just spend contesting/locking the locks for ConstString's global
>     string pools. Refactoring the code to not having to reaquire a
>     contested global lock for every DIE might help with improving
>     startup time.

I also feel obligated to point out that this code has been optimized and 
re-optimized by a number of people already. So all of the quick wins are 
likely gone already.

I am not saying that its not possible to improve the performance of this 
(in fact, I'm certain it can) -- however, such an effort will probably 
require making fundamental changes to the algorithm, rather than just 
using fancier data structures.

I don't want to sound too discouraging, but I think you ought to know 
what you're getting yourself into.

Good luck! (I mean it)

>>     I would like to have feedback on three parts:
>>
>>      1. In /ManualDWARFIndex::Preload() /I capture /this/ of the
>>         /ManualDWARFIndex/. As far as I could tell this is not a
>>         problem since the index is not relocated or deleted. However,
>>         I'm not that familiar with the architecture. Are there cases
>>         when the object is relocated or deleted before lldb stops?
While it's very unlikely, I don't think we can guarantee that the Module 
object holding the index is not deleted by the time the async thread 
runs. Such a thing might happen due to events totally beyond our 
control, such as the user calling SBTarget::RemoveModule.

This should be fixable by simply stashing the Module shared pointer.


>>      2. I use the /Module /mutex for synchronization because I didn't
>>         want to introduce a mutex in /ManualDWARFIndex /or
>>         /DWARFIndex/. Do you think this locking granularity is fine or
>>         should I create a dedicated mutex for it?
I think it should work, but a separate synchronization primitive might 
be cleaner. I might even go for a once_flag/call_once to also get the 
"runs once" behavior for free.

>>         Furthermore, I
>>         looked through the implementation
>>         of ManualDWARFIndex::/Index()/ and couldn't find any locking
>>         function in there. However, I might have missed something (or
>>         some of the underlying implementations change in the future)
>>         and there is a danger for a deadlock.
The lack of locking is not surprising because these functions already 
expect that the caller has taken the Module lock.

>>      3. /ManualDWARFIndex::Index()/ creates a thread pool internally.
>>         This means if multiple calls to/ ManualDWARFIndex::Index()
>>         /are executed at the same time, there might be more threads
>>         than cores. This might cause contention and decrease
>>         efficiency. (Thanks to Andy for pointing this out).

This is an interesting question for me, but I don't really have a good 
answer to it. On one hand, you could say that this is a situation that 
could occur already (though it wasn't always the case -- back when we 
had our own thread pool, it was process-wide and shared between 
different module instances). But OTOH, this does make it much easier for 
this situation to occur...

pl


More information about the lldb-commits mailing list