Re: Reducing the size of C++ executables - eliminating malloc
Olivier Galibert wrote: On Sun, Nov 12, 2006 at 02:46:58PM -0800, Michael Eager wrote: It would seem that the place to require the personality routine would be in the routine which causes the stack unwinding, not in every C++ object file, whether needed or not. Doesn't that otherwise very valid point of view break when you remember that new can throw exceptions? Folks who want to reduce the size of executables (e.g., embedded systems developers) know to avoid including malloc by using either static or stack allocation rather than using new. -- Michael Eager[EMAIL PROTECTED] 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
Re: Reducing the size of C++ executables - eliminating malloc
On Sun, Nov 12, 2006 at 02:46:58PM -0800, Michael Eager wrote: > It would seem that the place to require the personality > routine would be in the routine which causes the stack > unwinding, not in every C++ object file, whether needed > or not. Doesn't that otherwise very valid point of view break when you remember that new can throw exceptions? OG.
Re: Reducing the size of C++ executables - eliminating malloc
> GCC 4.1.1 for PowerPC generates a 162K executable for a > minimal program "int main() { return 0; }". GCC 3.4.1 > generated a 7.2K executable. Mark Mitchell mentioned the > same problem for ARM and proposed a patch to remove the > reference to malloc in atexit > (http://sourceware.org/ml/newlib/2006/msg00181.html). We've seen this on cell spu as well. And with only 256K total memory it was a really big deal for us. Our minimal program dropped from 10566 bytes to 2822 bytes (text + data + bss) with the attached completely unacceptable for merging patch. We were thinking that our platform has no need for more than 32 atexit handlers, and the proper solution is to make the code removed in the attached patch simply #ifdefed away for platforms like ours that are happy with 32 atexit handlers and are short on space. This seems to be the approach in the patch you linked to. -Joel Index: newlib-1.14.0/newlib/libc/stdlib/__atexit.c === --- newlib-1.14.0.orig/newlib/libc/stdlib/__atexit.c +++ newlib-1.14.0/newlib/libc/stdlib/__atexit.c @@ -9,6 +9,7 @@ #include "atexit.h" + /* * Register a function to be performed at exit or on shared library unload. */ @@ -24,6 +25,10 @@ _DEFUN (__register_exitproc, struct _on_exit_args * args; register struct _atexit *p; +#ifdef _REENT_SMALL + static struct _on_exit_args myargs; +#endif + #ifndef __SINGLE_THREAD__ __LOCK_INIT(static, lock); @@ -35,21 +40,10 @@ _DEFUN (__register_exitproc, _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0; if (p->_ind >= _ATEXIT_SIZE) { - p = (struct _atexit *) malloc (sizeof *p); - if (p == NULL) - { #ifndef __SINGLE_THREAD__ __lock_release(lock); #endif return -1; - } - p->_ind = 0; - p->_next = _GLOBAL_REENT->_atexit; - _GLOBAL_REENT->_atexit = p; -#ifndef _REENT_SMALL - p->_on_exit_args._fntypes = 0; - p->_on_exit_args._is_cxa = 0; -#endif } if (type != __et_atexit) @@ -58,7 +52,8 @@ _DEFUN (__register_exitproc, args = p->_on_exit_args_ptr; if (args == NULL) { - args = malloc (sizeof * p->_on_exit_args_ptr); +/* args = malloc (sizeof * p->_on_exit_args_ptr); */ + args = myargs; if (args == NULL) { #ifndef __SINGLE_THREAD__ Index: newlib-1.14.0/newlib/libc/stdlib/__call_atexit.c === --- newlib-1.14.0.orig/newlib/libc/stdlib/__call_atexit.c +++ newlib-1.14.0/newlib/libc/stdlib/__call_atexit.c @@ -68,10 +68,10 @@ _DEFUN (__call_exitprocs, (code, d), /* Remove empty block from the list. */ *lastp = p->_next; #ifdef _REENT_SMALL - if (args) - free (args); +/* if (args) */ +/* free (args); */ #endif - free (p); +/* free (p); */ p = *lastp; } else
Re: Reducing the size of C++ executables - eliminating malloc
Daniel Jacobowitz wrote: > On Sun, Nov 12, 2006 at 05:11:39PM -0800, Mark Mitchell wrote: >> Daniel Jacobowitz wrote: >> >>> If you try what Michael's been saying, you'll notice that trivial >>> C++ files get the personality routine reference even if they don't >>> have anything with a destructor which would need cleaning up. We ought >>> to be able to emit (somewhat smaller) unwind information which doesn't >>> reference the personality routine if it's going to have nothing to do, >>> shouldn't we? >> Certainly, there are at least some such cases. I guess a function whose >> only callees (if any) are no-throw functions, and which itself does not >> use "throw", does not need frame information. > > You've talked right past me, since I wasn't saying that... Well, for something like: int g() throw(); int f(int a) { return g() + a; } I don't think you ever have to unwind through "f". Exceptions are not allowed to leave "g", and nothing in "f" can throw, so as far as the EH systems is concerned, "f" doesn't even exist. I think we could just drop its frame info on the floor. This might be a relatively significant size improvement. >> Unless the entire program doesn't >> contain anything that needs cleaning up, we'll still need it in the >> final executable, > > Right. So if you use local variables with destructors, even though you > don't use exceptions, you'll get the personality routine. The linker > could straighten that out if we taught it to, though. Correct. It could notice that, globally, no throw-exception routines (i.e., __cxa_throw, and equivalents for other languages) were included and then discard the personality routine -- and, maybe, all of .eh_frame. You'd still have the cleanup code in function bodies, though, so if you really want minimum size, you still have to compile with -fno-exceptions. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: Reducing the size of C++ executables - eliminating malloc
On Sun, Nov 12, 2006 at 05:11:39PM -0800, Mark Mitchell wrote: > Daniel Jacobowitz wrote: > > > If you try what Michael's been saying, you'll notice that trivial > > C++ files get the personality routine reference even if they don't > > have anything with a destructor which would need cleaning up. We ought > > to be able to emit (somewhat smaller) unwind information which doesn't > > reference the personality routine if it's going to have nothing to do, > > shouldn't we? > > Certainly, there are at least some such cases. I guess a function whose > only callees (if any) are no-throw functions, and which itself does not > use "throw", does not need frame information. You've talked right past me, since I wasn't saying that... > However, I think you and Michael are right: we don't need to reference > the personality routine here. ... but this. > Unless the entire program doesn't > contain anything that needs cleaning up, we'll still need it in the > final executable, Right. So if you use local variables with destructors, even though you don't use exceptions, you'll get the personality routine. The linker could straighten that out if we taught it to, though. -- Daniel Jacobowitz CodeSourcery
Re: Reducing the size of C++ executables - eliminating malloc
On Mon, Nov 13, 2006 at 01:03:10AM +, Paul Brook wrote: > > C++ files get the personality routine reference even if they don't > > have anything with a destructor which would need cleaning up. We ought > > to be able to emit (somewhat smaller) unwind information which doesn't > > reference the personality routine if it's going to have nothing to do, > > shouldn't we? > > Ah, ok, sorry. ARM unwinding works a bit differently, and you always need a > personality routine. Right - which is why it was such a headache for us, isn't amenable to _Unwind_Backtrace / _Unwind_ForcedUnwind, et cetera. For .eh_frame, though, the personality routine is only necessary to run cleanups and check exception specs. -- Daniel Jacobowitz CodeSourcery
Re: Reducing the size of C++ executables - eliminating malloc
Daniel Jacobowitz wrote: > If you try what Michael's been saying, you'll notice that trivial > C++ files get the personality routine reference even if they don't > have anything with a destructor which would need cleaning up. We ought > to be able to emit (somewhat smaller) unwind information which doesn't > reference the personality routine if it's going to have nothing to do, > shouldn't we? Certainly, there are at least some such cases. I guess a function whose only callees (if any) are no-throw functions, and which itself does not use "throw", does not need frame information. But, for something like: extern void f(); void g() { f(); f(); } we do need unwind information, even though "g" has nothing to do with exceptions. However, I think you and Michael are right: we don't need to reference the personality routine here. Unless the entire program doesn't contain anything that needs cleaning up, we'll still need it in the final executable, but omitting it would make our object files smaller, and unwinding a little faster, since we don't call personality routines that aren't there. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: Reducing the size of C++ executables - eliminating malloc
On Monday 13 November 2006 00:53, Daniel Jacobowitz wrote: > On Sun, Nov 12, 2006 at 11:17:14PM +, Paul Brook wrote: > > The code being unwound through (ie. with frame data) needs to be able to > > say "I need routine X if __Unwind_Raise is used anywhere in this > > program". I'm not aware of any way of doing this, other than trying it > > and starting again if you guessed wrong. > > Again, IIRC ARM's linker does something clever here. Of course the ABI > in use there is somewhat different, but I suspect it could be adapted. Probably. I don't think the ABI differences are relevant here. > On Sun, Nov 12, 2006 at 03:20:48PM -0800, Mark Mitchell wrote: > > But, the way the ABI works requires a reference from each unit which may > > cause unwinding. Even if you lose the personality routine, you will > > still have the exception tables, which themselves are a significant > > cost. If you don't want to pay for exceptions, you really have to > > compile with -fno-exceptions. In that case, certainly, we should be > > able to avoid pulling in the personality routine. > > If you try what Michael's been saying, you'll notice that trivial > C++ files get the personality routine reference even if they don't > have anything with a destructor which would need cleaning up. We ought > to be able to emit (somewhat smaller) unwind information which doesn't > reference the personality routine if it's going to have nothing to do, > shouldn't we? Ah, ok, sorry. ARM unwinding works a bit differently, and you always need a personality routine. Paul
Re: Reducing the size of C++ executables - eliminating malloc
On Sun, Nov 12, 2006 at 11:17:14PM +, Paul Brook wrote: > The code being unwound through (ie. with frame data) needs to be able to > say "I need routine X if __Unwind_Raise is used anywhere in this program". > I'm not aware of any way of doing this, other than trying it and starting > again if you guessed wrong. Again, IIRC ARM's linker does something clever here. Of course the ABI in use there is somewhat different, but I suspect it could be adapted. On Sun, Nov 12, 2006 at 03:20:48PM -0800, Mark Mitchell wrote: > But, the way the ABI works requires a reference from each unit which may > cause unwinding. Even if you lose the personality routine, you will > still have the exception tables, which themselves are a significant > cost. If you don't want to pay for exceptions, you really have to > compile with -fno-exceptions. In that case, certainly, we should be > able to avoid pulling in the personality routine. If you try what Michael's been saying, you'll notice that trivial C++ files get the personality routine reference even if they don't have anything with a destructor which would need cleaning up. We ought to be able to emit (somewhat smaller) unwind information which doesn't reference the personality routine if it's going to have nothing to do, shouldn't we? -- Daniel Jacobowitz CodeSourcery
Re: Reducing the size of C++ executables - eliminating malloc
Mark Mitchell wrote: But, the way the ABI works requires a reference from each unit which may cause unwinding. Even if you lose the personality routine, you will still have the exception tables, which themselves are a significant cost. If you don't want to pay for exceptions, you really have to compile with -fno-exceptions. In that case, certainly, we should be able to avoid pulling in the personality routine. I think that we are actually in agreement, for the most part. The routines which need unwinding should have a reference to the personality module. Routines which don't need unwinding shouldn't have a superfluous reference to it. There is a check in doing_eh() in except.c which checks that -fexceptions is set if any exception-specific functions are used. It seems that this would be the place to generate the reference to __gxx_personality_v0. -- Michael Eager[EMAIL PROTECTED] 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
Re: Reducing the size of C++ executables - eliminating malloc
Michael Eager wrote: > Mark Mitchell wrote: >> Michael Eager wrote: >>> Why should the personality routine be included in all C++ programs? >> >> Because all non-trivial, exceptions-enabled programs, may need to do >> stack unwinding. > > It would seem that the place to require the personality > routine would be in the routine which causes the stack > unwinding, not in every C++ object file, whether needed > or not. But, the way the ABI works requires a reference from each unit which may cause unwinding. Even if you lose the personality routine, you will still have the exception tables, which themselves are a significant cost. If you don't want to pay for exceptions, you really have to compile with -fno-exceptions. In that case, certainly, we should be able to avoid pulling in the personality routine. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: Reducing the size of C++ executables - eliminating malloc
On Sunday 12 November 2006 22:46, Michael Eager wrote: > Mark Mitchell wrote: > > Michael Eager wrote: > >> Why should the personality routine be included in all C++ programs? > > > > Because all non-trivial, exceptions-enabled programs, may need to do > > stack unwinding. > > It would seem that the place to require the personality > routine would be in the routine which causes the stack > unwinding, not in every C++ object file, whether needed > or not. The problem is that the places that knows we're using exceptions don't know how to do the stack unwinding, or what we're unwinding through. Only the code being unwound knows how to do the unwinding. The frame unwind information contains a function pointer that is called to interpret the rest of the frame data. eg. C, C++ and Java all have different exception table formats, and different personality routines to interpret those tables. The code that calls throw(), and the implementation of thow() don't know which of these routines are needed. The code being unwound through (ie. with frame data) needs to be able to say "I need routine X if __Unwind_Raise is used anywhere in this program". I'm not aware of any way of doing this, other than trying it and starting again if you guessed wrong. Paul
Re: Reducing the size of C++ executables - eliminating malloc
Mark Mitchell wrote: Michael Eager wrote: Why should the personality routine be included in all C++ programs? Because all non-trivial, exceptions-enabled programs, may need to do stack unwinding. It would seem that the place to require the personality routine would be in the routine which causes the stack unwinding, not in every C++ object file, whether needed or not. For embedded targets, there are many C++ programs which are non-trivial and which do not require exception handling. My thoughts: 1) Exception support should be included only when used. 2) The default for -exceptions should be target dependent. -- Michael Eager[EMAIL PROTECTED] 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
Re: Reducing the size of C++ executables - eliminating malloc
Michael Eager wrote: > Mark Mitchell wrote: >>> Generating __gxx_personality_v0 is suppressed with the -fno-exceptions >>> flag, but it would seem better if this symbol were only generated >>> when catch/throw was used. This happens in cxx_init_decl_processing(), >>> which is called before it's known whether or not EH is really needed. >> >> I believe that you need the personality routine if you will be unwinding >> through a function, which is why -fno-exceptions is the test. > > You mean unwinding stack frames to handle a thrown exception? > > That's true, but shouldn't this only be included when there > exceptions are used? No, it must be included if exceptions are enabled, and there are any objects which might require cleanups, which, in most C++ programs, is equivalent to there are any objects with a destructor. > One of the C++ percepts is that there > is no overhead for features which are not used. That objective does not hold for space, especially in the presence of exceptions. > Why should the personality routine be included in all C++ programs? Because all non-trivial, exceptions-enabled programs, may need to do stack unwinding. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: Reducing the size of C++ executables - eliminating malloc
Mark Mitchell wrote: Generating __gxx_personality_v0 is suppressed with the -fno-exceptions flag, but it would seem better if this symbol were only generated when catch/throw was used. This happens in cxx_init_decl_processing(), which is called before it's known whether or not EH is really needed. I believe that you need the personality routine if you will be unwinding through a function, which is why -fno-exceptions is the test. You mean unwinding stack frames to handle a thrown exception? That's true, but shouldn't this only be included when there exceptions are used? One of the C++ percepts is that there is no overhead for features which are not used. Why should the personality routine be included in all C++ programs? -- Michael Eager[EMAIL PROTECTED] 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
Re: Reducing the size of C++ executables - eliminating malloc
Michael Eager wrote: > Preallocating space is a good thing, particularly if the size > can be computed at compile time. It's a little bit more awkward > if it has to be calculated at link time. It's a bit awkward, but it's also one of the clever tricks ARM's proprietary linker uses, and we should use it too! > Generating __gxx_personality_v0 is suppressed with the -fno-exceptions > flag, but it would seem better if this symbol were only generated > when catch/throw was used. This happens in cxx_init_decl_processing(), > which is called before it's known whether or not EH is really needed. I believe that you need the personality routine if you will be unwinding through a function, which is why -fno-exceptions is the test. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713
Re: Reducing the size of C++ executables - eliminating malloc
Mark Mitchell wrote: Michael Eager wrote: GCC 4.1.1 for PowerPC generates a 162K executable for a minimal program "int main() { return 0; }". GCC 3.4.1 generated a 7.2K executable. Mark Mitchell mentioned the same problem for ARM and proposed a patch to remove the reference to malloc in atexit (http://sourceware.org/ml/newlib/2006/msg00181.html). There are references to malloc in eh_alloc.c and unwind-dw2-fde.c. It looks like these are being included even when there are no exception handlers. Any suggestions on how to eliminate the references to these routines? These aren't full implementation sketches, but, yes, we can do better. Here are some ideas: 1. For the DWARF unwind stuff, have the linker work out how much space is required and pre-allocate it. The space required is a statically knowable property of the executable, modulo dynamic linking, and on the cases where we care most (bare-metal) we don't have to worry about dynamic linking. (If you can afford a dynamic linker, you can probably afford malloc, and it's in a shared library.) 2. For the EH stuff, the maximum size of an exception is also statically knowable, again assuming no dynamic linking. The maximum exception nesting depth (i.e., the number of simultaneously active exceptions) is not, though. So, here, what I think you want is a small, statically allocated stack, at least as big as the biggest exception, out of which you allocate exception objects. Happily, we already have this, in the form of "emergency_buffer" -- although it uses a compile-time estimate of the biggest object, rather than having the linker fill it in, as would be ideal. But, in the no-malloc case, just fall back to the emergency mode. You could also declare malloc "weak" in that file, and just not call it if the value is zero. That way, if malloc is around, you can use it -- but if it's not, you use the emergency buffer. Put the emergency_buffer in a separate file (rather than in eh_alloc.cc), so that users can provide their own implementation to control the size, overriding the one in the library. Preallocating space is a good thing, particularly if the size can be computed at compile time. It's a little bit more awkward if it has to be calculated at link time. On the other hand, why should either DWARF unwind or the eh_* files be included if C++ exception handling is not used? The minimal executable has a reference to __gxx_personality_v0. This is defined in eh_personality.o, which has a reference to __cxa_allocate_exception in eh_alloc.o. So this seems to be the thread which pulls in all the other pieces. Generating __gxx_personality_v0 is suppressed with the -fno-exceptions flag, but it would seem better if this symbol were only generated when catch/throw was used. This happens in cxx_init_decl_processing(), which is called before it's known whether or not EH is really needed. Any suggestions on how to move this test later? -- Michael Eager[EMAIL PROTECTED] 1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
Re: Reducing the size of C++ executables - eliminating malloc
Michael Eager wrote: > GCC 4.1.1 for PowerPC generates a 162K executable for a > minimal program "int main() { return 0; }". GCC 3.4.1 > generated a 7.2K executable. Mark Mitchell mentioned the > same problem for ARM and proposed a patch to remove the > reference to malloc in atexit > (http://sourceware.org/ml/newlib/2006/msg00181.html). > > There are references to malloc in eh_alloc.c and > unwind-dw2-fde.c. It looks like these are being > included even when there are no exception handlers. > > Any suggestions on how to eliminate the references > to these routines? These aren't full implementation sketches, but, yes, we can do better. Here are some ideas: 1. For the DWARF unwind stuff, have the linker work out how much space is required and pre-allocate it. The space required is a statically knowable property of the executable, modulo dynamic linking, and on the cases where we care most (bare-metal) we don't have to worry about dynamic linking. (If you can afford a dynamic linker, you can probably afford malloc, and it's in a shared library.) 2. For the EH stuff, the maximum size of an exception is also statically knowable, again assuming no dynamic linking. The maximum exception nesting depth (i.e., the number of simultaneously active exceptions) is not, though. So, here, what I think you want is a small, statically allocated stack, at least as big as the biggest exception, out of which you allocate exception objects. Happily, we already have this, in the form of "emergency_buffer" -- although it uses a compile-time estimate of the biggest object, rather than having the linker fill it in, as would be ideal. But, in the no-malloc case, just fall back to the emergency mode. You could also declare malloc "weak" in that file, and just not call it if the value is zero. That way, if malloc is around, you can use it -- but if it's not, you use the emergency buffer. Put the emergency_buffer in a separate file (rather than in eh_alloc.cc), so that users can provide their own implementation to control the size, overriding the one in the library. -- Mark Mitchell CodeSourcery [EMAIL PROTECTED] (650) 331-3385 x713