Hi,
while I was happy using obstacks in other parts of the compiler I thought
they would provide a handy solution for the XNEWVECs/XRESIZEVECs in
df-scan.c, especially df_install_refs() which is the heaviest malloc()
user after the rest of my patches.
In the process I realised that obstacks weren't exactly suitable (thanks
matz for helping on IRC), nevertheless I have a patch which is stable, a
bit faster and more memory friendly (don't know why, but RSS memory for
common non-pathological compilations, was smaller). However after trying
various incorrect changes I'm aware that there are leaks in there that
can't be closed without dirty hacks, so I gave up.
I'm posting the simplest but stable version of my changes and would really
like to hear ideas. There are "holes" in the obstack that should have been
free'd, but in the end I didn't see memory increase. I don't know what
would happen for huge functions that keep the obstack alive for long, I
didn't have such testcase. Finally, I think my next try will involve
converting the chains to pool_alloc'ed linked list, do you think that
makes sense?
Thanks,
Dimitris
=== modified file 'gcc/df-scan.c'
--- gcc/df-scan.c 2012-07-16 11:32:42 +0000
+++ gcc/df-scan.c 2012-08-20 14:01:59 +0000
@@ -184,6 +184,17 @@ struct df_scan_problem_data
bitmap_obstack insn_bitmaps;
};
+/* Obstack for storing all of all of
+ insn_info->{defs,uses,eq_uses,mw_hardregs} and
+ bb_info->artificial_{defs,uses}. */
+static struct obstack df_refs_obstack;
+
+/* Keep the obstack initialised (only 4k overhead) and use this pointer to
+ actually empty it fast. */
+static void *df_first_refs_obj;
+static int df_refs_obstack_is_init;
+
+
typedef struct df_scan_bb_info *df_scan_bb_info_t;
@@ -193,36 +204,13 @@ df_scan_free_internal (void)
{
struct df_scan_problem_data *problem_data
= (struct df_scan_problem_data *) df_scan->problem_data;
- unsigned int i;
- basic_block bb;
- /* The vectors that hold the refs are not pool allocated because
- they come in many sizes. This makes them impossible to delete
- all at once. */
- for (i = 0; i < DF_INSN_SIZE(); i++)
- {
- struct df_insn_info *insn_info = DF_INSN_UID_GET(i);
- /* Skip the insns that have no insn_info or have been
- deleted. */
- if (insn_info)
- {
- df_scan_free_ref_vec (insn_info->defs);
- df_scan_free_ref_vec (insn_info->uses);
- df_scan_free_ref_vec (insn_info->eq_uses);
- df_scan_free_mws_vec (insn_info->mw_hardregs);
- }
- }
-
- FOR_ALL_BB (bb)
- {
- unsigned int bb_index = bb->index;
- struct df_scan_bb_info *bb_info = df_scan_get_bb_info (bb_index);
- if (bb_info)
- {
- df_scan_free_ref_vec (bb_info->artificial_defs);
- df_scan_free_ref_vec (bb_info->artificial_uses);
- }
- }
+ /* Delete at once all vectors that hold the refs (all of
+ insn_info->{defs,uses,eq_uses,mw_hardregs} and
+ bb_info->artificial_{defs,uses}) but keep the obstack initialised, so
+ that it's ready for more BBs. */
+ obstack_free (&df_refs_obstack, df_first_refs_obj);
+ df_first_refs_obj = NULL;
free (df->def_info.refs);
free (df->def_info.begin);
@@ -364,6 +352,14 @@ df_scan_alloc (bitmap all_blocks ATTRIBU
bb_info->artificial_uses = NULL;
}
+ if (! df_refs_obstack_is_init)
+ {
+ obstack_init (&df_refs_obstack);
+ df_refs_obstack_is_init = 1;
+ }
+ gcc_assert (df_first_refs_obj == NULL);
+ df_first_refs_obj = XOBNEW (&df_refs_obstack, void *);
+
bitmap_initialize (&df->hardware_regs_used, &problem_data->reg_bitmaps);
bitmap_initialize (&df->regular_block_artificial_uses,
&problem_data->reg_bitmaps);
bitmap_initialize (&df->eh_block_artificial_uses,
&problem_data->reg_bitmaps);
@@ -791,9 +787,15 @@ df_install_ref_incremental (df_ref ref)
}
ref_rec = *ref_rec_ptr;
+ /* fprintf (stderr, "count:%d ref_rec:%p\n", count, ref_rec); */
if (count)
{
- ref_rec = XRESIZEVEC (df_ref, ref_rec, count+2);
+ /* Impossible to actually know if ref_rec was malloc'ed or obstack'ed
+ thus we might have a leak here! */
+ df_ref *ref_rec2 = XOBNEWVEC (&df_refs_obstack, df_ref, count+2);
+ memcpy (ref_rec2, ref_rec, count*sizeof(df_ref));
+ /* free (ref_rec); */
+ ref_rec = ref_rec2;
*ref_rec_ptr = ref_rec;
ref_rec[count] = ref;
ref_rec[count+1] = NULL;
@@ -801,7 +803,7 @@ df_install_ref_incremental (df_ref ref)
}
else
{
- df_ref *ref_rec = XNEWVEC (df_ref, 2);
+ ref_rec = XOBNEWVEC (&df_refs_obstack, df_ref, 2);
ref_rec[0] = ref;
ref_rec[1] = NULL;
*ref_rec_ptr = ref_rec;
@@ -1070,8 +1072,9 @@ df_ref_chain_delete (df_ref *ref_rec)
/* If the list is empty, it has a special shared element that is not
to be deleted. */
- if (*start)
- free (start);
+ /* if (*start) */
+ /* free (start); */
+ /* obstack_free'd alltogether in the end of df pass. */
}
@@ -2611,7 +2615,7 @@ df_install_refs (basic_block bb,
count = VEC_length (df_ref, old_vec);
if (count)
{
- df_ref *new_vec = XNEWVEC (df_ref, count + 1);
+ df_ref *new_vec = XOBNEWVEC (&df_refs_obstack, df_ref, count + 1);
bool add_to_table;
df_ref this_ref;
unsigned int ix;