[PATCH] GAS: Don't shrink the frag size below the default
Maciej W. Rozycki
macro@codesourcery.com
Thu Aug 2 20:16:00 GMT 2012
Hi,
While debugging the MIPS issue recorded here:
http://sourceware.org/ml/binutils/2012-08/msg00043.html
I made an interesting observation as to how the size of frags used to
store machine code generated is determined.
As noted in that issue, frags are placed in memory allocated dynamically
with obstack_alloc. This is a GNU extension and is implemented in iberty
and glibc; the former is bundled with binutils and I haven't checked if a
glibc copy is ever used if used as the system C library. Obstack memory
is allocated in chunks and a frag can be freely grown up to the amount of
memory available in the obstack it has been put in. Once the frag cannot
be grown any further it has to be closed and a new frag created, that will
be placed in a newly allocated obstack.
The size of the chunk and therefore any obstack allocated, by default,
depends on the programming model used on the host. GAS starts by using
the default size. This size is calculated as 4096 bytes minus a
programming-model specific amount calculated based on sizeof (union
fooround) defined internally, that I believe can be for *nix systems, that
we may be potentially concerned about, one of 4, 8, 12 or 16, and the
corresponding amount comes out as a value between 16 and 32, so the
remaining space is between 4064 and 4080.
Interestingly enough, this size is applied to the first obstack only. As
soon as another obstack is needed GAS switches to using about the minimum
size possible and starts requesting further obstacks in amounts that are
double the instruction size only, that for the MIPS target means either 4
or 8 bytes. How miserable! Obstack allocation code uses some arbitrary
look-ahead heuristics and actually provides some more, but that is is
still 84 bytes only, so beyond the first obstack GAS starts thrashing with
requests for new obstacks. This is I believe an unnecessary memory and
performance waste.
By how the offending code looks I gather the intent was to provide for
large obstacks where an excessively big chunk of data needs to be placed
in a single frag (the associated comment quotes 2GB!), but inadvertently
the code does not check for the allocation size getting smaller than the
reasonable default. There is normally no penalty from using the default
even for the smallest frags possible, because as many individual frags can
be placed in a single obstack as will fit there. Therefore I believe this
is a missed optimisation.
Here is a change to address this. It changes obstack allocation code
such that the size requested never goes below the default; however it can
be increased as the caller sees fit to satisfy large pieces of data.
I have regression-tested it against my current list of targets that is a
superset of what Alan uses. No problems triggered. OK to apply?
2012-08-02 Maciej W. Rozycki <macro@codesourcery.com>
gas/
* frags.c (frag_grow): Never shrink the obstack size requested
below the default.
Maciej
binutils-gas-frag-obstack-chunk-size.diff
Index: binutils-fsf-trunk-quilt/gas/frags.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/frags.c 2011-12-12 23:49:56.000000000 +0000
+++ binutils-fsf-trunk-quilt/gas/frags.c 2012-07-09 23:59:16.560713789 +0100
@@ -101,9 +101,11 @@ frag_grow (unsigned int nchars)
if (newc < 0)
as_fatal (_("can't extend frag %u chars"), nchars);
- /* Force to allocate at least NEWC bytes. */
+ /* Force to allocate at least NEWC bytes, but not less than the
+ default. */
oldc = obstack_chunk_size (&frchain_now->frch_obstack);
- obstack_chunk_size (&frchain_now->frch_obstack) = newc;
+ if (newc > oldc)
+ obstack_chunk_size (&frchain_now->frch_obstack) = newc;
while (obstack_room (&frchain_now->frch_obstack) < nchars)
{
More information about the Binutils
mailing list