* Loading some symbols, when, and index-cache
@ 2025-04-06 15:07 Lluís Batlle i Rossell via Gdb
2025-04-07 12:05 ` Guinevere Larsen via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Lluís Batlle i Rossell via Gdb @ 2025-04-06 15:07 UTC (permalink / raw)
To: gdb
Hello,
I'm trying to make sense of what symbols are loaded and when, in gdb.
For example, opening an elf file, it will build some index (usable as
index-cache) of some symbols, but not all.
If I do "gdb gdb" (for my compiled gdb), and then "maint print stat" I
get:
Number of "minimal" symbols read: 33435
Number of read CUs: 0
Number of unread CUs: 682
Why haven't all CUs been read, and incorporated into the index? Because at
file loading the CUs symbols index is generated with worker threads (read.c),
therefore, potentially using all cores of the system. And the result would
be cached in the index-cache.
Because the next thing I notice is that when I type "list def<TAB>" to get
symbol completion, a very slow single-thread symbol expansion causes many CUs
to be loaded. After which:, "maint print stat":
Number of "minimal" symbols read: 33435
Number of "full" symbols read: 2732412
Number of "types" defined: 4292812
Number of symbol tables: 57075
Number of symbol tables with line tables: 9608
Number of symbol tables with blockvectors: 351
Number of read CUs: 351
Number of unread CUs: 331
Is there any way this work can be done ahead? Why the index-cache only helps
for the "minimal" symbols? How can we use the cache for all symbols? Why not
all CUs have been loaded yet?
Regards,
Lluís.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-06 15:07 Loading some symbols, when, and index-cache Lluís Batlle i Rossell via Gdb
@ 2025-04-07 12:05 ` Guinevere Larsen via Gdb
2025-04-07 12:21 ` Lluís Batlle i Rossell via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Guinevere Larsen via Gdb @ 2025-04-07 12:05 UTC (permalink / raw)
To: Lluís Batlle i Rossell, gdb
On 4/6/25 12:07 PM, Lluís Batlle i Rossell via Gdb wrote:
> Hello,
>
> I'm trying to make sense of what symbols are loaded and when, in gdb.
> For example, opening an elf file, it will build some index (usable as
> index-cache) of some symbols, but not all.
>
> If I do "gdb gdb" (for my compiled gdb), and then "maint print stat" I
> get:
>
> Number of "minimal" symbols read: 33435
> Number of read CUs: 0
> Number of unread CUs: 682
>
> Why haven't all CUs been read, and incorporated into the index? Because at
> file loading the CUs symbols index is generated with worker threads (read.c),
> therefore, potentially using all cores of the system. And the result would
> be cached in the index-cache.
>
> Because the next thing I notice is that when I type "list def<TAB>" to get
> symbol completion, a very slow single-thread symbol expansion causes many CUs
> to be loaded. After which:, "maint print stat":
>
> Number of "minimal" symbols read: 33435
> Number of "full" symbols read: 2732412
> Number of "types" defined: 4292812
> Number of symbol tables: 57075
> Number of symbol tables with line tables: 9608
> Number of symbol tables with blockvectors: 351
> Number of read CUs: 351
> Number of unread CUs: 331
>
> Is there any way this work can be done ahead? Why the index-cache only helps
> for the "minimal" symbols? How can we use the cache for all symbols? Why not
> all CUs have been loaded yet?
I can't answer all questions, but I can help with two of them:
> is there any way this work can be done ahead?
Yes! you can use the --readnow option to force gdb to read all symbols
of the added inferior... however
> Why not all CUs have been loaded yet?
It is super slow. Your example completion managed to avoid reading half
of all symbols and you already felt the time, doing twice that work
every time you start up your debug section would be very noticeable for
little gain considering that most debug sessions won't span all the
codebase.
To get a sense of how much of a slowdown that is, I tested locally and:
$ time ./gdb gdb --batch -ex "complete list def" #Basically the same as
you did
./gdb gdb --batch -ex "complete list def" 42.40s user 1.19s system 120%
cpu 36.243 total
$ time ./gdb gdb --batch --readnow -ex "complete list def"
./gdb gdb --batch --readnow -ex "complete list def" 58.32s user 1.79s
system 100% cpu 1:00.08 total
So even with the slower expansion, GDB is still faster than if we had
all symbols being read at the start, and this isn't even taking into
account the memory usage.
I can't help with the cache stuff, though, never touched it.
--
Cheers,
Guinevere Larsen
She/Her/Hers
>
> Regards,
> Lluís.
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-07 12:05 ` Guinevere Larsen via Gdb
@ 2025-04-07 12:21 ` Lluís Batlle i Rossell via Gdb
2025-04-07 16:01 ` Simon Marchi via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Lluís Batlle i Rossell via Gdb @ 2025-04-07 12:21 UTC (permalink / raw)
To: Guinevere Larsen; +Cc: gdb
On Mon, Apr 07, 2025 at 09:05:10AM -0300, Guinevere Larsen via Gdb wrote:
> $ time ./gdb gdb --batch -ex "complete list def" #Basically the same as you
> did
> ./gdb gdb --batch -ex "complete list def" 42.40s user 1.19s system 120% cpu
> 36.243 total
> $ time ./gdb gdb --batch --readnow -ex "complete list def"
> ./gdb gdb --batch --readnow -ex "complete list def" 58.32s user 1.79s
> system 100% cpu 1:00.08 total
>
> So even with the slower expansion, GDB is still faster than if we had all
> symbols being read at the start, and this isn't even taking into account the
> memory usage.
There are two points important:
The cache should allow having a big file on disk that it's just read into
memory with zero work and then all symbols are ready to search. But
apparently this happens only with the "minimal" set of symbols, which is
far from enough for a tab completion.
And 2nd, at gdb ELF file loading, thread workers are launched to read the
symbols from the CUs. Again, these seem to load only the "minimal" set of
symbols. In your example of 1 minute that load of CUs runs single thread.
I can't even tell that the code behaves correctly. One could say that the
initial load of CUs multithread should load ALL symbols, and same about
caching. Or at least that could be an option. Otherwise, the things they
are meant to run faster become quite limited, while the really-slow
usual completions go single-thread uncached, taking for you 1 minute.
Thanks,
Lluís.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-07 12:21 ` Lluís Batlle i Rossell via Gdb
@ 2025-04-07 16:01 ` Simon Marchi via Gdb
2025-04-08 7:29 ` Lluís Batlle i Rossell via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Simon Marchi via Gdb @ 2025-04-07 16:01 UTC (permalink / raw)
To: Lluís Batlle i Rossell, Guinevere Larsen; +Cc: gdb
On 2025-04-07 08:21, Lluís Batlle i Rossell via Gdb wrote:
> On Mon, Apr 07, 2025 at 09:05:10AM -0300, Guinevere Larsen via Gdb wrote:
>> $ time ./gdb gdb --batch -ex "complete list def" #Basically the same as you
>> did
>> ./gdb gdb --batch -ex "complete list def" 42.40s user 1.19s system 120% cpu
>> 36.243 total
>> $ time ./gdb gdb --batch --readnow -ex "complete list def"
>> ./gdb gdb --batch --readnow -ex "complete list def" 58.32s user 1.79s
>> system 100% cpu 1:00.08 total
>>
>> So even with the slower expansion, GDB is still faster than if we had all
>> symbols being read at the start, and this isn't even taking into account the
>> memory usage.
>
> There are two points important:
>
> The cache should allow having a big file on disk that it's just read into
> memory with zero work and then all symbols are ready to search. But
> apparently this happens only with the "minimal" set of symbols, which is
> far from enough for a tab completion.
>
> And 2nd, at gdb ELF file loading, thread workers are launched to read the
> symbols from the CUs. Again, these seem to load only the "minimal" set of
> symbols. In your example of 1 minute that load of CUs runs single thread.
>
> I can't even tell that the code behaves correctly. One could say that the
> initial load of CUs multithread should load ALL symbols, and same about
> caching. Or at least that could be an option. Otherwise, the things they
> are meant to run faster become quite limited, while the really-slow
> usual completions go single-thread uncached, taking for you 1 minute.
>
> Thanks,
> Lluís.
Hi Lluís,
I think you misunderstand the role of what's called the index-cache
(meaning it's perhaps not documented properly). I will summarize the
process that GDB takes from start to being able to use a symbol. In
this situation no index is present in the binary file nor in the index
cache.
1. You do "gdb myprogram".
2. GDB reads the ELF symbols into what it calls "minimal symbols"
internally.
3. In parallel, GDB demangles the names Ada/C++/whatever symbol names
4. GDB notices there is some DWARF info, so it opens it and lists the
compilation units by hopping from header to header
5. In parallel (the background workers you referred to), GDB scans each
compilation unit to create an in-memory index. What this index
essentially consists of is a mapping of names to which compilation
unit contains that name. We only need the names of variables,
functions and types that the user could possibly refer to in an
expression. While traversing the debug info to create that index,
GDB skips most the of debug info, making it quite fast.
6. You type "print foo" in the CLI, or another expression
containing a symbol name.
7. The expression parser asks the DWARF subsystem: expand all
compilation units that contain a variable or function named "foo".
The index is looked up to identify the candidate compilation units.
8. Serially, the DWARF subsystem fully reads those compilation units
to create some "symtab"s, which is a detailed internal representation
of everything that could be found in the debug info.
9. The core is then able to look up "foo" in the symtabs, find
the relevant symbol, and continue the expression evaluation.
To avoid doing the work in step #5, it is possible to ask compilers to
generate a name index that ressembles the name -> compilation unit index
that GDB would produce. Alternatively, GDB is able to add that index to
a binary that doesn't have it (see the gdb-add-index command). The
index cache is a third way to access that pre-computed index, which
requires no user intervention (other than toggling the index-cache on).
If the index-cache enabled, and no pre-computed index is present
already, GDB will save it in ~/.cache/gdb, allowing it to read it back
later. It's exactly the same data that gdb-add-index would add to the
binary.
The index cache was added because historically, using an index was
_much_ faster than having GDB generate its in-memory index (it used
what's called internally "partial symbols", it no longer uses them for
DWARF). So it was useful, because the second time you loaded a binary
was much faster than the first time. Nowadays, with the new-ish
parallelized scanner I described in step #5, the time difference between
using a pre-computed index or generating it on the fly is not that big.
The -readnow option that Guinevere talked about skips the in-memory
index generation (or skips reading the pre-computed index if there is
one) and goes directly to expanding all compilation units into symtabs
right away. I would typically not recommend using this day-to-day,
other than maybe if you need to work around an indexer bug.
When you type "list def<TAB>" and it's very slow, it's likely that a lot
of compilation units have a symbol that starts with "def", so a lot of
compilation units get expanded into symtabs. Only after that happens
can the core of GDB search generate completion list by searching the
symtabs. That's not optimal, there's certainly room for improvement
here (I too get frustrated by very slow tab-completion, to the point
where I often avoid it).
I must point out that a pending patch series changes a bit how symbols
are looked up and symtabs expanded, which will probably make what I
described somewhat outdated:
[PATCH v2 00/28] Search symbols via quick API
https://inbox.sourceware.org/gdb-patches/20250402-search-in-psyms-v2-0-ea91704487cb@tromey.com/T/#m737dd42bf8767f5719ffac7eb147977c4b0f2829
Simon
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-07 16:01 ` Simon Marchi via Gdb
@ 2025-04-08 7:29 ` Lluís Batlle i Rossell via Gdb
2025-04-08 13:43 ` Simon Marchi via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Lluís Batlle i Rossell via Gdb @ 2025-04-08 7:29 UTC (permalink / raw)
To: Simon Marchi; +Cc: Guinevere Larsen, gdb
On Mon, Apr 07, 2025 at 12:01:38PM -0400, Simon Marchi wrote:
> I must point out that a pending patch series changes a bit how symbols
> are looked up and symtabs expanded, which will probably make what I
> described somewhat outdated:
>
> [PATCH v2 00/28] Search symbols via quick API
> https://inbox.sourceware.org/gdb-patches/20250402-search-in-psyms-v2-0-ea91704487cb@tromey.com/T/#m737dd42bf8767f5719ffac7eb147977c4b0f2829
Thank you a lot for your detailed explanation! It has been very helpful.
Definitely I had no idea of the "partial symbols" piece. Now all makes
sense. I will think of areas where that can be improved.
I will check those pending patches. Are they likely to be integrated?
Thank you,
Lluís.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-08 7:29 ` Lluís Batlle i Rossell via Gdb
@ 2025-04-08 13:43 ` Simon Marchi via Gdb
2025-04-09 7:42 ` Lluís Batlle i Rossell via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Simon Marchi via Gdb @ 2025-04-08 13:43 UTC (permalink / raw)
To: Lluís Batlle i Rossell; +Cc: Guinevere Larsen, gdb
On 2025-04-08 03:29, Lluís Batlle i Rossell wrote:
> I will check those pending patches. Are they likely to be integrated?
Yes, it's from Tom Tromey, so it's probably good :). I hope to find the
time to look at them soon, to add my approval.
Simon
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-08 13:43 ` Simon Marchi via Gdb
@ 2025-04-09 7:42 ` Lluís Batlle i Rossell via Gdb
2025-04-22 15:31 ` Simon Marchi via Gdb
0 siblings, 1 reply; 8+ messages in thread
From: Lluís Batlle i Rossell via Gdb @ 2025-04-09 7:42 UTC (permalink / raw)
To: Simon Marchi; +Cc: Guinevere Larsen, gdb
On Tue, Apr 08, 2025 at 09:43:45AM -0400, Simon Marchi wrote:
> On 2025-04-08 03:29, Lluís Batlle i Rossell wrote:
> > I will check those pending patches. Are they likely to be integrated?
>
> Yes, it's from Tom Tromey, so it's probably good :). I hope to find the
> time to look at them soon, to add my approval.
I thought that one interesting approach would be to restrict the
tab-completion to the "minimal" symbols, as a user config option. I wonder
if that set is more than enough for many cases.
What are the occasions where only "minimal" symbols are searched, and
occasions where "all" symbols are searched (by means of partial symbols +
CU loading)?
Regards,
Lluís.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Loading some symbols, when, and index-cache
2025-04-09 7:42 ` Lluís Batlle i Rossell via Gdb
@ 2025-04-22 15:31 ` Simon Marchi via Gdb
0 siblings, 0 replies; 8+ messages in thread
From: Simon Marchi via Gdb @ 2025-04-22 15:31 UTC (permalink / raw)
To: Lluís Batlle i Rossell; +Cc: Guinevere Larsen, gdb
On 4/9/25 3:42 AM, Lluís Batlle i Rossell wrote:
> On Tue, Apr 08, 2025 at 09:43:45AM -0400, Simon Marchi wrote:
>> On 2025-04-08 03:29, Lluís Batlle i Rossell wrote:
>>> I will check those pending patches. Are they likely to be integrated?
>>
>> Yes, it's from Tom Tromey, so it's probably good :). I hope to find the
>> time to look at them soon, to add my approval.
>
> I thought that one interesting approach would be to restrict the
> tab-completion to the "minimal" symbols, as a user config option. I wonder
> if that set is more than enough for many cases.
Not really, because you can tab-complete much more than minimal symbols.
In production apps, minimal symbols only contain exported functions and
variables. They also don't know anything about types.
> What are the occasions where only "minimal" symbols are searched, and
> occasions where "all" symbols are searched (by means of partial symbols +
> CU loading)?
I don't know for sure. I think that full symbols are always searched
first when trying to resolve a symbol name to a symbol.
Simon
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-04-22 15:31 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-06 15:07 Loading some symbols, when, and index-cache Lluís Batlle i Rossell via Gdb
2025-04-07 12:05 ` Guinevere Larsen via Gdb
2025-04-07 12:21 ` Lluís Batlle i Rossell via Gdb
2025-04-07 16:01 ` Simon Marchi via Gdb
2025-04-08 7:29 ` Lluís Batlle i Rossell via Gdb
2025-04-08 13:43 ` Simon Marchi via Gdb
2025-04-09 7:42 ` Lluís Batlle i Rossell via Gdb
2025-04-22 15:31 ` Simon Marchi via Gdb
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox