Memory footprint/compile time explosion caused by the tree inliner

Eric Botcazou ebotcazou@libertysurf.fr
Thu Apr 17 22:59:00 GMT 2003


Hi,

PR optimization/10160 reports a huge compile time regression (4h30min vs a 
few minutes) on the 3.3 branch wrt the 3.2 branch for LyX/QT on Sparc. The 
time is mostly (85%) spent in the scheduler but the regression is caused by 
the tree inliner.

Here are some numbers at -O2:

                               peak    time
GCC 3.2.3pre                   63MB   1min38s
GCC 3.3pre
 max-inline-insns-single=150   89MB   1min18s
 max-inline-insns-single=175   89MB   1min36s
 max-inline-insns-single=200   89MB   2min10s
 max-inline-insns-single=205   90MB   2min38s
 max-inline-insns-single=210   90MB   3min37s
 max-inline-insns-single=215  157MB   5min35s
 max-inline-insns-single=225  185MB   8min19s
 max-inline-insns-single=235 >256MB   ??

The default is max-inline-insns-single=300.


Interestingly, max-inline-insns doesn't play any role:

 max-inline-insns=300 >256MB   ??
 max-inline-insns=200 >256MB   ??
 max-inline-insns=100 >256MB   ??

The default is max-inline-single-insns=600.


So, once we have reached a threshold on the number of insns for a single 
functions, a bunch of little functions (constructors in this case) gets 
inlined, totally out of control.

For example, one constructor grows from 128 stmts to 15437 stmts (154370 
insns according to the fixed conversion factor), that is more than 100 
times. Given that the scheduler is at least O(n^2), the game is over.


The problem is the new heuristics of the tree inliner:

      int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
		     + currfn_insns;
      /* In the extreme case that we have exceeded the recursive inlining
         limit by a huge factor (128), we just say no. Should not happen
         in real life.  */
      if (sum_insns > MAX_INLINE_INSNS * 128)
	 inlinable = 0;
      /* If we did not hit the extreme limit, we use a linear function
         with slope -1/MAX_INLINE_SLOPE to exceedingly decrease the
         allowable size. We always allow a size of MIN_INLINE_INSNS
         though.  */
      else if ((sum_insns > MAX_INLINE_INSNS)
	       && (currfn_insns > MIN_INLINE_INSNS))
	{
	  int max_curr = MAX_INLINE_INSNS_SINGLE
			- (sum_insns - MAX_INLINE_INSNS) / MAX_INLINE_SLOPE;
	  if (currfn_insns > max_curr)
	    inlinable = 0;
	}

The constructors are small, so we always have

	currfn_insns <= MIN_INLINE_INSNS.

So the limit is not max-inline-insns but max-inline-insns * 128, that is 
76800 insns (7680 stmts) per inlining group!

I did some testing on this arbitrary factor 128:

       peak    time
 16   >256 MB  ??
  8   >256 MB  ??
  4   >256 MB  ??
  3   >256 MB  ??
  2    110 MB  5min20s
  1.5  82  MB  2min37s


It clearly appears that the tree inliner lacks some global control on a per 
function basis. I think we should implement a cut, absolute or relative, so 
as to avoid this kind of explosion in compile time and memory footprint.

-- 
Eric Botcazou



More information about the Gcc mailing list