Message ID | 20140108183415.GK892@tucnak.redhat.com |
---|---|
State | New |
Headers | show |
Jakub Jelinek <jakub@redhat.com> writes: > 2014-01-08 Jakub Jelinek <jakub@redhat.com> > > * target-globals.c (save_target_globals): Allocate most of the > structs using GC in payload of target_globals struct instead > of allocating them on the heap. Looks good to me FWIW. I don't know either way about the one-big-blob thing. Note that we'll still leak memory when deleting TARGET_OPTION_NODEs because target_ira_int and target_lra_int have pointers to heap-allocated storage. Thanks, Richard
On Wed, Jan 08, 2014 at 07:41:26PM +0000, Richard Sandiford wrote: > Jakub Jelinek <jakub@redhat.com> writes: > > 2014-01-08 Jakub Jelinek <jakub@redhat.com> > > > > * target-globals.c (save_target_globals): Allocate most of the > > structs using GC in payload of target_globals struct instead > > of allocating them on the heap. > > Looks good to me FWIW. I don't know either way about the one-big-blob thing. > > Note that we'll still leak memory when deleting TARGET_OPTION_NODEs > because target_ira_int and target_lra_int have pointers to heap-allocated > storage. Yeah, perhaps that is something to fix incrementally. But, at least we will not leak ~ 0.5MB per (unique) target attribute used on some unused function. Jakub
On 01/08/2014 10:34 AM, Jakub Jelinek wrote: > struct target_globals *g; > - > - g = ggc_alloc_target_globals (); > - g->flag_state = XCNEW (struct target_flag_state); > - g->regs = XCNEW (struct target_regs); > + struct target_globals_extra { > + struct target_globals g; > + struct target_flag_state flag_state; > + struct target_regs regs; > + struct target_hard_regs hard_regs; > + struct target_reload reload; > + struct target_expmed expmed; > + struct target_optabs optabs; > + struct target_cfgloop cfgloop; > + struct target_ira ira; > + struct target_ira_int ira_int; > + struct target_lra_int lra_int; > + struct target_builtins builtins; > + struct target_gcse gcse; > + struct target_bb_reorder bb_reorder; > + struct target_lower_subreg lower_subreg; > + } *p; > + p = (struct target_globals_extra *) > + ggc_internal_cleared_alloc_stat (sizeof (struct target_globals_extra) > + PASS_MEM_STAT); > + g = (struct target_globals *) p; > + g->flag_state = &p->flag_state; > + g->regs = &p->regs; > g->rtl = ggc_alloc_cleared_target_rtl (); So, we're relying on something pointing to G, thus keeping the whole P alive? I suppose that works but it's fairly ugly that's for sure. As for the extra ~500k wasted on x86_64, we can either fix our gc allocator to do something sensible with these high-order allocations, or we can do nearly this same trick only with libc. I.e. struct target_globals_extra { struct target_flag_state flag_state; struct target_regs regs; struct target_hard_regs hard_regs; struct target_reload reload; struct target_expmed expmed; struct target_optabs optabs; struct target_cfgloop cfgloop; struct target_ira ira; struct target_ira_int ira_int; struct target_lra_int lra_int; struct target_builtins builtins; struct target_gcse gcse; struct target_bb_reorder bb_reorder; struct target_lower_subreg lower_subreg; } *p; g = ggc_alloc_target_globals (); p = XCNEW (target_globals_extra); ... r~
On Thu, Jan 09, 2014 at 08:25:31AM -0800, Richard Henderson wrote: > > + p = (struct target_globals_extra *) > > + ggc_internal_cleared_alloc_stat (sizeof (struct target_globals_extra) > > + PASS_MEM_STAT); > > + g = (struct target_globals *) p; > > + g->flag_state = &p->flag_state; > > + g->regs = &p->regs; > > g->rtl = ggc_alloc_cleared_target_rtl (); > > So, we're relying on something pointing to G, thus keeping the whole P alive? > I suppose that works but it's fairly ugly that's for sure. The separate structures aren't really installed individually, they are always installed together through restore_target_globals. As long as the any FUNCTION_DECL with such TARGET_OPTION_NODE exists, it will be reachable. The reason why it needs to be GC is: 1) in two of these target_* structures there are embedded rtxes etc. the GC needs to see 2) if all FUNCTION_DECL with such combination of target attributes are GCed, we'd leak memory > As for the extra ~500k wasted on x86_64, we can either fix our gc allocator to > do something sensible with these high-order allocations, or we can do nearly > this same trick only with libc. I.e. > > struct target_globals_extra { > struct target_flag_state flag_state; > struct target_regs regs; > struct target_hard_regs hard_regs; > struct target_reload reload; > struct target_expmed expmed; > struct target_optabs optabs; > struct target_cfgloop cfgloop; > struct target_ira ira; > struct target_ira_int ira_int; > struct target_lra_int lra_int; > struct target_builtins builtins; > struct target_gcse gcse; > struct target_bb_reorder bb_reorder; > struct target_lower_subreg lower_subreg; > } *p; > > g = ggc_alloc_target_globals (); > p = XCNEW (target_globals_extra); > ... That would be fine for 1), but would mean 2). It is also fine to GC allocate each structure individually, but some (like bb_reorder) are say just 4 bytes long, so it might be overkill. As noted by Richard S., IRA/LRA still puts pointers to heap allocated objects into some of the structures, so there is some leak anyway, but not as big. Jakub
On 01/09/2014 08:35 AM, Jakub Jelinek wrote: > That would be fine for 1), but would mean 2). It is also fine to GC > allocate each structure individually, but some (like bb_reorder) are say > just 4 bytes long, so it might be overkill. Hmm.. Perhaps define the whole structure as you do, but somewhere global enough that ggc-page.c can see it, and add to the extra_order_size_table? I don't know how much memory wastage there would be there, but I can't imagine it's as much as 0.5MB. r~
--- gcc/target-globals.c.jj 2014-01-08 10:23:22.000000000 +0100 +++ gcc/target-globals.c 2014-01-08 14:00:13.183231122 +0100 @@ -68,24 +68,43 @@ struct target_globals * save_target_globals (void) { struct target_globals *g; - - g = ggc_alloc_target_globals (); - g->flag_state = XCNEW (struct target_flag_state); - g->regs = XCNEW (struct target_regs); + struct target_globals_extra { + struct target_globals g; + struct target_flag_state flag_state; + struct target_regs regs; + struct target_hard_regs hard_regs; + struct target_reload reload; + struct target_expmed expmed; + struct target_optabs optabs; + struct target_cfgloop cfgloop; + struct target_ira ira; + struct target_ira_int ira_int; + struct target_lra_int lra_int; + struct target_builtins builtins; + struct target_gcse gcse; + struct target_bb_reorder bb_reorder; + struct target_lower_subreg lower_subreg; + } *p; + p = (struct target_globals_extra *) + ggc_internal_cleared_alloc_stat (sizeof (struct target_globals_extra) + PASS_MEM_STAT); + g = (struct target_globals *) p; + g->flag_state = &p->flag_state; + g->regs = &p->regs; g->rtl = ggc_alloc_cleared_target_rtl (); - g->hard_regs = XCNEW (struct target_hard_regs); - g->reload = XCNEW (struct target_reload); - g->expmed = XCNEW (struct target_expmed); - g->optabs = XCNEW (struct target_optabs); + g->hard_regs = &p->hard_regs; + g->reload = &p->reload; + g->expmed = &p->expmed; + g->optabs = &p->optabs; g->libfuncs = ggc_alloc_cleared_target_libfuncs (); - g->cfgloop = XCNEW (struct target_cfgloop); - g->ira = XCNEW (struct target_ira); - g->ira_int = XCNEW (struct target_ira_int); - g->lra_int = XCNEW (struct target_lra_int); - g->builtins = XCNEW (struct target_builtins); - g->gcse = XCNEW (struct target_gcse); - g->bb_reorder = XCNEW (struct target_bb_reorder); - g->lower_subreg = XCNEW (struct target_lower_subreg); + g->cfgloop = &p->cfgloop; + g->ira = &p->ira; + g->ira_int = &p->ira_int; + g->lra_int = &p->lra_int; + g->builtins = &p->builtins; + g->gcse = &p->gcse; + g->bb_reorder = &p->bb_reorder; + g->lower_subreg = &p->lower_subreg; restore_target_globals (g); init_reg_sets (); target_reinit ();