Discussion:
Performance issue of -var-list-children on structs with many members and remote targets
(too old to reply)
Raphael Zulliger
2014-08-08 07:25:13 UTC
Permalink
Raw Message
This mail is about a proposal for improving GDB/GDBServer speed for
-var-list-children on large structs.

I have the following performance issue: Using Eclipse/CDT, expanding a
large structs (roughly 1000 members) on an embedded target (target
extended-remote) to inspect the members of a struct takes about 15
seconds on a not that out-dated Windows PC.

According to my investigation, the major amount of this time is spent
exchanging data between GDB and our own GDBServer implementation (which
btw. also runs on the same PC, not on the embedded system). Assume we
have the following code:

struct S {
double a, b, c;
} g_s;

int main() {
return 0;
}

When expanding g_s in Eclipse/Luna the following happens with gdb/master
(Aug 4 2014) on Ubuntu 14.04/64:

499,882 37-var-list-children var2
499,882
37^done,numchild="1",children=[child={name="var2.public",exp="public",numchild="3"}],has_mor\
e="0"
499,882 (gdb)
499,883 38-var-list-children var2.public
499,884 &"Sending packet: $m601050,8#fd..."
499,884 &"Packet received: 0000000000000000\n"
499,884 &"Sending packet: $m601058,8#05..."
499,884 &"Packet received: 0000000000000000\n"
499,884 &"Sending packet: $m601060,8#fe..."
499,884 &"Packet received: 0000000000000000\n"
499,884
38^done,numchild="3",children=[child={name="var2.public.a",exp="a",numchild="0",type="double\
"},child={name="var2.public.b",exp="b",numchild="0",type="double"},child={name="var2.public.c",exp="\
c",numchild="0",type="double"}],has_more="0"
499,884 (gdb)
499,885 39-var-info-path-expression var2.public.a
499,885 40-var-info-path-expression var2.public.b
499,885 41-var-info-path-expression var2.public.c
499,885 39^done,path_expr="((g_s).a)"
499,885 (gdb)
499,886 40^done,path_expr="((g_s).b)"
499,886 (gdb)
499,886 41^done,path_expr="((g_s).c)"
499,886 (gdb)
499,892 42-var-evaluate-expression var2.public.a
499,893 42^done,value="0"
499,893 (gdb)

Projecting these traces back to my large-scale example with about 1000
members in 'struct S', it's the following part that consumes the major
amount of time (measured using "Process monitor"'s activity feature
which clearly shows high network traffic and CPU consumption of both,
GDB and our GDBServer processes during roughly 10 seconds):

499,883 38-var-list-children var2.public
499,884 &"Sending packet: $m601050,8#fd..."
499,884 &"Packet received: 0000000000000000\n"
499,884 &"Sending packet: $m601058,8#05..."
499,884 &"Packet received: 0000000000000000\n"
499,884 &"Sending packet: $m601060,8#fe..."
499,884 &"Packet received: 0000000000000000\n"

Now my simple question: Couldn't GDB be tweaked to get the struct member
values by just one call (because members within a struct are guaranteed
to be consecutive, aren't they?):

499,883 38-var-list-children var2.public
499,884 &"Sending packet: $m601050,24#??"

I guess this would dramatically increase overall performance.

I would really like to see such an improvement in GDB. Therefore, I'd be
very happy to hear your thoughts and suggestion. Thinks like: What
problems (e.g. border cases) could arise when implementing this? Where
to start in the GDB code for such a modification? Or do there exist any
GDB switches to improve performance on such operations? etc...

Thanks a lot!
Raphael
Yao Qi
2014-08-08 10:31:20 UTC
Permalink
Raw Message
On 08/08/2014 03:25 PM, Raphael Zulliger wrote:
> Now my simple question: Couldn't GDB be tweaked to get the struct member
> values by just one call (because members within a struct are guaranteed
> to be consecutive, aren't they?):
>
> 499,883 38-var-list-children var2.public
> 499,884 &"Sending packet: $m601050,24#??"
>
> I guess this would dramatically increase overall performance.
>
> I would really like to see such an improvement in GDB. Therefore, I'd be
> very happy to hear your thoughts and suggestion. Thinks like: What
> problems (e.g. border cases) could arise when implementing this? Where
> to start in the GDB code for such a modification? Or do there exist any
> GDB switches to improve performance on such operations? etc...

I have no idea how to merge multiple reads into one.

Cache is used in GDB to read code and stack from target, which
increases performance to some extent (See target_read_code and
target_read_stack). However, cache is NOT used to read general data.
Probably, you can make general data reading use cache too.

--
Yao (齐尧)
Raphael Zulliger
2014-08-11 14:57:20 UTC
Permalink
Raw Message
On 08/08/2014 12:31 PM, Yao Qi wrote:
> On 08/08/2014 03:25 PM, Raphael Zulliger wrote:
>> Now my simple question: Couldn't GDB be tweaked to get the struct member
>> values by just one call (because members within a struct are guaranteed
>> to be consecutive, aren't they?):
>>
>> 499,883 38-var-list-children var2.public
>> 499,884 &"Sending packet: $m601050,24#??"
>>
>> I guess this would dramatically increase overall performance.
>>
>> I would really like to see such an improvement in GDB. Therefore, I'd be
>> very happy to hear your thoughts and suggestion. Thinks like: What
>> problems (e.g. border cases) could arise when implementing this? Where
>> to start in the GDB code for such a modification? Or do there exist any
>> GDB switches to improve performance on such operations? etc...
> I have no idea how to merge multiple reads into one.
Thanks for your response!

I guess you are aware of the fact that -data-evaluate-expression is
already getting the data in the most efficient way, see e.g.:

-data-evaluate-expression --thread 1 --frame 0 g_s
&"Sending packet: $m601050,18#2e..."
&"Packet received: 000000000000f03f00000000000000000000000000000000\n"
^done,value="{a = 1, b = 0, c = 0}"

Couldn't we do the same during a '-var-update' for a struct like varobj
and let it propagate the values to it's children, instead of letting the
children update their values?

An implementation could probably indeed be done with a cache system, as
suggested by you below. Then the "only" changes would be to implement
that cache and to update struct-like varobj *before* traversing their
children. Would something like that make sense?
>
> Cache is used in GDB to read code and stack from target, which
> increases performance to some extent (See target_read_code and
> target_read_stack). However, cache is NOT used to read general data.
> Probably, you can make general data reading use cache too.
In our use case, we're debugging real-time systems in which (global)
data often changes at a rapid rate and thus the cache alone wouldn't
help much.
Loading...