public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][C++] Save memory and reallocations in name-lookup
@ 2012-08-17 11:20 Richard Guenther
  2012-08-17 11:41 ` Gabriel Dos Reis
  2012-08-17 11:44 ` Gabriel Dos Reis
  0 siblings, 2 replies; 8+ messages in thread
From: Richard Guenther @ 2012-08-17 11:20 UTC (permalink / raw)
  To: gcc-patches


This reduces the number of re-allocations and the amount of memory
wasted by store_binding.  Previously, on a cut-down testcase from
PR54146 we can see (--enable-gather-detailed-mem-stats -fmem-report
output):

cp/name-lookup.c:5874 (store_binding)              12033504: 1.6%    
8564032: 2.4%          0: 0.0%    2398752:12.9%      30134

that's the GC VEC (re-)allocation which wastes 2MB and re-allocates
30134 times.  After the patch we have

cp/name-lookup.c:5911 (store_bindings)              1243648: 0.2%     
352240: 0.1%          0: 0.0%     154064: 0.9%       9407
cp/name-lookup.c:5945 (store_class_bindings)        9643632: 1.3%     
120160: 0.0%          0: 0.0%     209376: 1.3%      10109

which means only 19516 reallocations and 350kb wasted memory.  The
compile-time effects are neutral (name-lookup is 1.0+-0.05s on
the reduced testcase) - a slightly different version which omitted
the temporary vector but walked things twice was consistently slower
(about 1.2s).  It seems we can end up with duplicates in the
names chain of store_bindings (not sure if that is intended).

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Ok if that passes?

Thanks,
Richard.

2012-08-17  Richard Guenther  <rguenther@suse.de>

	cp/
	* name-lookup.c (store_binding_p): New predicate, split out from ...
	(store_binding): ... here.  Always store binding and require
	target vector with enough space.
	(store_bindings): Collect to store bindings and reserve space
	for them, then store them.
	(store_class_bindings): Likewise.

Index: gcc/cp/name-lookup.c
===================================================================
*** gcc/cp/name-lookup.c	(revision 190471)
--- gcc/cp/name-lookup.c	(working copy)
*************** pushtag (tree name, tree type, tag_scope
*** 5855,5877 ****
     scope isn't enough, because more binding levels may be pushed.  */
  struct saved_scope *scope_chain;
  
! /* If ID has not already been marked, add an appropriate binding to
!    *OLD_BINDINGS.  */
  
  static void
  store_binding (tree id, VEC(cxx_saved_binding,gc) **old_bindings)
  {
    cxx_saved_binding *saved;
  
!   if (!id || !IDENTIFIER_BINDING (id))
!     return;
! 
!   if (IDENTIFIER_MARKED (id))
!     return;
  
    IDENTIFIER_MARKED (id) = 1;
  
!   saved = VEC_safe_push (cxx_saved_binding, gc, *old_bindings, NULL);
    saved->identifier = id;
    saved->binding = IDENTIFIER_BINDING (id);
    saved->real_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
--- 5855,5887 ----
     scope isn't enough, because more binding levels may be pushed.  */
  struct saved_scope *scope_chain;
  
! /* Return true if ID has not already been marked.  */
! 
! static inline bool
! store_binding_p (tree id)
! {
!   if (!id || !IDENTIFIER_BINDING (id))
!     return false;
! 
!   if (IDENTIFIER_MARKED (id))
!     return false;
! 
!   return true;
! }
! 
! /* Add an appropriate binding to *OLD_BINDINGS which needs to already
!    have enough space reserved.  */
  
  static void
  store_binding (tree id, VEC(cxx_saved_binding,gc) **old_bindings)
  {
    cxx_saved_binding *saved;
  
!   gcc_checking_assert (store_binding_p (id));
  
    IDENTIFIER_MARKED (id) = 1;
  
!   saved = VEC_quick_push (cxx_saved_binding, *old_bindings, NULL);
    saved->identifier = id;
    saved->binding = IDENTIFIER_BINDING (id);
    saved->real_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
*************** store_binding (tree id, VEC(cxx_saved_bi
*** 5881,5899 ****
  static void
  store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
  {
!   tree t;
  
    bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
    for (t = names; t; t = TREE_CHAIN (t))
      {
-       tree id;
- 
        if (TREE_CODE (t) == TREE_LIST)
  	id = TREE_PURPOSE (t);
        else
  	id = DECL_NAME (t);
  
!       store_binding (id, old_bindings);
      }
    timevar_cond_stop (TV_NAME_LOOKUP, subtime);
  }
--- 5891,5922 ----
  static void
  store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
  {
!   static VEC(tree,heap) *bindings_need_stored = NULL;
!   tree t, id;
!   size_t i;
  
    bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
    for (t = names; t; t = TREE_CHAIN (t))
      {
        if (TREE_CODE (t) == TREE_LIST)
  	id = TREE_PURPOSE (t);
        else
  	id = DECL_NAME (t);
  
!       if (store_binding_p (id))
! 	VEC_safe_push(tree, heap, bindings_need_stored, id);
!     }
!   if (!VEC_empty (tree, bindings_need_stored))
!     {
!       VEC_reserve_exact (cxx_saved_binding, gc, *old_bindings,
! 			 VEC_length (tree, bindings_need_stored));
!       for (i = 0; VEC_iterate(tree, bindings_need_stored, i, id); ++i)
! 	{
! 	  /* We can appearantly have duplicates in NAMES.  */
! 	  if (store_binding_p (id))
! 	    store_binding (id, old_bindings);
! 	}
!       VEC_truncate (tree, bindings_need_stored, 0);
      }
    timevar_cond_stop (TV_NAME_LOOKUP, subtime);
  }
*************** static void
*** 5905,5916 ****
  store_class_bindings (VEC(cp_class_binding,gc) *names,
  		      VEC(cxx_saved_binding,gc) **old_bindings)
  {
    size_t i;
    cp_class_binding *cb;
  
    bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
    for (i = 0; VEC_iterate(cp_class_binding, names, i, cb); ++i)
!     store_binding (cb->identifier, old_bindings);
    timevar_cond_stop (TV_NAME_LOOKUP, subtime);
  }
  
--- 5928,5950 ----
  store_class_bindings (VEC(cp_class_binding,gc) *names,
  		      VEC(cxx_saved_binding,gc) **old_bindings)
  {
+   static VEC(tree,heap) *bindings_need_stored = NULL;
    size_t i;
    cp_class_binding *cb;
  
    bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
    for (i = 0; VEC_iterate(cp_class_binding, names, i, cb); ++i)
!     if (store_binding_p (cb->identifier))
!       VEC_safe_push (tree, heap, bindings_need_stored, cb->identifier);
!   if (!VEC_empty (tree, bindings_need_stored))
!     {
!       tree id;
!       VEC_reserve_exact (cxx_saved_binding, gc, *old_bindings,
! 			 VEC_length (tree, bindings_need_stored));
!       for (i = 0; VEC_iterate(tree, bindings_need_stored, i, id); ++i)
! 	store_binding (id, old_bindings);
!       VEC_truncate (tree, bindings_need_stored, 0);
!     }
    timevar_cond_stop (TV_NAME_LOOKUP, subtime);
  }
  

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:20 [PATCH][C++] Save memory and reallocations in name-lookup Richard Guenther
@ 2012-08-17 11:41 ` Gabriel Dos Reis
  2012-08-17 11:58   ` Richard Guenther
  2012-08-17 11:59   ` Jakub Jelinek
  2012-08-17 11:44 ` Gabriel Dos Reis
  1 sibling, 2 replies; 8+ messages in thread
From: Gabriel Dos Reis @ 2012-08-17 11:41 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches

On Fri, Aug 17, 2012 at 6:17 AM, Richard Guenther <rguenther@suse.de> wrote:
>
> This reduces the number of re-allocations and the amount of memory
> wasted by store_binding.  Previously, on a cut-down testcase from
> PR54146 we can see (--enable-gather-detailed-mem-stats -fmem-report
> output):
>
> cp/name-lookup.c:5874 (store_binding)              12033504: 1.6%
> 8564032: 2.4%          0: 0.0%    2398752:12.9%      30134
>
> that's the GC VEC (re-)allocation which wastes 2MB and re-allocates
> 30134 times.  After the patch we have
>
> cp/name-lookup.c:5911 (store_bindings)              1243648: 0.2%
> 352240: 0.1%          0: 0.0%     154064: 0.9%       9407
> cp/name-lookup.c:5945 (store_class_bindings)        9643632: 1.3%
> 120160: 0.0%          0: 0.0%     209376: 1.3%      10109

Nice saving.  As original author of the name lookup refactoring and improvement,
I am delighted to see we can do much better.

I am however concerned with:

>   static void
>   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
>   {
> !   static VEC(tree,heap) *bindings_need_stored = NULL;

I would be more comfortable to see the cache be on per-scope
(e.g. namespace scope) basis as opposed
a blanket global cache stored in a global variable.

-- Gaby

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:20 [PATCH][C++] Save memory and reallocations in name-lookup Richard Guenther
  2012-08-17 11:41 ` Gabriel Dos Reis
@ 2012-08-17 11:44 ` Gabriel Dos Reis
  1 sibling, 0 replies; 8+ messages in thread
From: Gabriel Dos Reis @ 2012-08-17 11:44 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches

On Fri, Aug 17, 2012 at 6:17 AM, Richard Guenther <rguenther@suse.de> wrote:

> which means only 19516 reallocations and 350kb wasted memory.  The
> compile-time effects are neutral (name-lookup is 1.0+-0.05s on
> the reduced testcase) - a slightly different version which omitted
> the temporary vector but walked things twice was consistently slower
> (about 1.2s).

Funny; I found something similar 10 years ago :-/

> It seems we can end up with duplicates in the
> names chain of store_bindings (not sure if that is intended).
>

the chain is supposed to implement a stack, not a set.

-- Gaby

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:41 ` Gabriel Dos Reis
@ 2012-08-17 11:58   ` Richard Guenther
  2012-08-17 11:59   ` Jakub Jelinek
  1 sibling, 0 replies; 8+ messages in thread
From: Richard Guenther @ 2012-08-17 11:58 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc-patches

On Fri, 17 Aug 2012, Gabriel Dos Reis wrote:

> On Fri, Aug 17, 2012 at 6:17 AM, Richard Guenther <rguenther@suse.de> wrote:
> >
> > This reduces the number of re-allocations and the amount of memory
> > wasted by store_binding.  Previously, on a cut-down testcase from
> > PR54146 we can see (--enable-gather-detailed-mem-stats -fmem-report
> > output):
> >
> > cp/name-lookup.c:5874 (store_binding)              12033504: 1.6%
> > 8564032: 2.4%          0: 0.0%    2398752:12.9%      30134
> >
> > that's the GC VEC (re-)allocation which wastes 2MB and re-allocates
> > 30134 times.  After the patch we have
> >
> > cp/name-lookup.c:5911 (store_bindings)              1243648: 0.2%
> > 352240: 0.1%          0: 0.0%     154064: 0.9%       9407
> > cp/name-lookup.c:5945 (store_class_bindings)        9643632: 1.3%
> > 120160: 0.0%          0: 0.0%     209376: 1.3%      10109
> 
> Nice saving.  As original author of the name lookup refactoring and improvement,
> I am delighted to see we can do much better.
> 
> I am however concerned with:
> 
> >   static void
> >   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
> >   {
> > !   static VEC(tree,heap) *bindings_need_stored = NULL;
> 
> I would be more comfortable to see the cache be on per-scope
> (e.g. namespace scope) basis as opposed
> a blanket global cache stored in a global variable.

It's a "cache" only to not need a malloc/free for each store_bindings,
store_class_bindings invocation.  I've made it function local for
code cleaniness.  We're using this kind of trick elsewhere in the
compiler.

> > It seems we can end up with duplicates in the
> > names chain of store_bindings (not sure if that is intended).
>
> the chain is supposed to implement a stack, not a set.

Ah, I see.  That explains it.

Richard.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:41 ` Gabriel Dos Reis
  2012-08-17 11:58   ` Richard Guenther
@ 2012-08-17 11:59   ` Jakub Jelinek
  2012-08-17 12:46     ` Gabriel Dos Reis
  2012-08-18  6:40     ` Dimitrios Apostolou
  1 sibling, 2 replies; 8+ messages in thread
From: Jakub Jelinek @ 2012-08-17 11:59 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Richard Guenther, gcc-patches

On Fri, Aug 17, 2012 at 06:41:37AM -0500, Gabriel Dos Reis wrote:
> I am however concerned with:
> 
> >   static void
> >   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
> >   {
> > !   static VEC(tree,heap) *bindings_need_stored = NULL;
> 
> I would be more comfortable to see the cache be on per-scope
> (e.g. namespace scope) basis as opposed
> a blanket global cache stored in a global variable.

It is not any kind of cache.  It could be in theory an automatic variable
vector pointer, it is only used during that function.  The reason why it is
static variable instead is just to avoid constant allocation/deallocation
of the vector, this way after the first call it will be already allocated
(but, upon entry to store_bindings will always be empty).

	Jakub

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:59   ` Jakub Jelinek
@ 2012-08-17 12:46     ` Gabriel Dos Reis
  2012-08-18  6:40     ` Dimitrios Apostolou
  1 sibling, 0 replies; 8+ messages in thread
From: Gabriel Dos Reis @ 2012-08-17 12:46 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Guenther, gcc-patches

On Fri, Aug 17, 2012 at 6:55 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Aug 17, 2012 at 06:41:37AM -0500, Gabriel Dos Reis wrote:
>> I am however concerned with:
>>
>> >   static void
>> >   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
>> >   {
>> > !   static VEC(tree,heap) *bindings_need_stored = NULL;
>>
>> I would be more comfortable to see the cache be on per-scope
>> (e.g. namespace scope) basis as opposed
>> a blanket global cache stored in a global variable.
>
> It is not any kind of cache.  It could be in theory an automatic variable
> vector pointer, it is only used during that function.  The reason why it is
> static variable instead is just to avoid constant allocation/deallocation
> of the vector, this way after the first call it will be already allocated
> (but, upon entry to store_bindings will always be empty).

Ah, OK.  The patch is OK then.
Thanks,

-- Gaby

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-17 11:59   ` Jakub Jelinek
  2012-08-17 12:46     ` Gabriel Dos Reis
@ 2012-08-18  6:40     ` Dimitrios Apostolou
  2012-08-20  7:24       ` Richard Guenther
  1 sibling, 1 reply; 8+ messages in thread
From: Dimitrios Apostolou @ 2012-08-18  6:40 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Gabriel Dos Reis, Richard Guenther, gcc-patches

Hi,

On Fri, 17 Aug 2012, Jakub Jelinek wrote:
> On Fri, Aug 17, 2012 at 06:41:37AM -0500, Gabriel Dos Reis wrote:
>> I am however concerned with:
>>
>>>   static void
>>>   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
>>>   {
>>> !   static VEC(tree,heap) *bindings_need_stored = NULL;
>>
>> I would be more comfortable to see the cache be on per-scope
>> (e.g. namespace scope) basis as opposed
>> a blanket global cache stored in a global variable.
>
> It is not any kind of cache.  It could be in theory an automatic variable
> vector pointer, it is only used during that function.  The reason why it is
> static variable instead is just to avoid constant allocation/deallocation
> of the vector, this way after the first call it will be already allocated
> (but, upon entry to store_bindings will always be empty).

Why not use stack vector of sufficient size for most cases then? I usually 
do something like:

       VEC (tree, stack) *bindings_need_stored = VEC_alloc (tree, stack, 32);
       ...
       VEC_free (tree, stack, bindings_need_stored);

if I've measured that 32 (or whatever) is enough for most cases. I 
don't have a clue about this case though.


Dimitris

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH][C++] Save memory and reallocations in name-lookup
  2012-08-18  6:40     ` Dimitrios Apostolou
@ 2012-08-20  7:24       ` Richard Guenther
  0 siblings, 0 replies; 8+ messages in thread
From: Richard Guenther @ 2012-08-20  7:24 UTC (permalink / raw)
  To: Dimitrios Apostolou; +Cc: Jakub Jelinek, Gabriel Dos Reis, gcc-patches

On Sat, 18 Aug 2012, Dimitrios Apostolou wrote:

> Hi,
> 
> On Fri, 17 Aug 2012, Jakub Jelinek wrote:
> > On Fri, Aug 17, 2012 at 06:41:37AM -0500, Gabriel Dos Reis wrote:
> > > I am however concerned with:
> > > 
> > > >   static void
> > > >   store_bindings (tree names, VEC(cxx_saved_binding,gc) **old_bindings)
> > > >   {
> > > > !   static VEC(tree,heap) *bindings_need_stored = NULL;
> > > 
> > > I would be more comfortable to see the cache be on per-scope
> > > (e.g. namespace scope) basis as opposed
> > > a blanket global cache stored in a global variable.
> > 
> > It is not any kind of cache.  It could be in theory an automatic variable
> > vector pointer, it is only used during that function.  The reason why it is
> > static variable instead is just to avoid constant allocation/deallocation
> > of the vector, this way after the first call it will be already allocated
> > (but, upon entry to store_bindings will always be empty).
> 
> Why not use stack vector of sufficient size for most cases then? I usually do
> something like:
> 
>       VEC (tree, stack) *bindings_need_stored = VEC_alloc (tree, stack, 32);
>       ...
>       VEC_free (tree, stack, bindings_need_stored);
> 
> if I've measured that 32 (or whatever) is enough for most cases. I don't have
> a clue about this case though.

I considered that, but I'm not sure it would be an improvement.  We'd
have a re-allocation and free in some cases then.

Richard.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-08-20  7:24 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-17 11:20 [PATCH][C++] Save memory and reallocations in name-lookup Richard Guenther
2012-08-17 11:41 ` Gabriel Dos Reis
2012-08-17 11:58   ` Richard Guenther
2012-08-17 11:59   ` Jakub Jelinek
2012-08-17 12:46     ` Gabriel Dos Reis
2012-08-18  6:40     ` Dimitrios Apostolou
2012-08-20  7:24       ` Richard Guenther
2012-08-17 11:44 ` Gabriel Dos Reis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).