DSPRelated.com
Forums

And -- pow! My memory was gone.

Started by Tim Wescott February 21, 2011
I'm shaking the box, trying to get the software to settle enough to fit 
into a 64kB memory space.  This is made difficult by the fact that it's 
a human-interface rich environment with a bit of extra fat contributed 
by the fact that I'm writing in C++.

This is for an application that worked just peachy-keen on a captive 
vendor's tool set, but which is too big using gnu tools.  It's to be 
expected, I suppose.

As soon as I saw all of the I/O junk in the map file I realized that 
maybe I shouldn't be using sprintf (even if it _did_ fit before).  So I 
took it out, and rather than contort my code, I'm writing a replacement 
for just the formats that I'm using (yes, I know, bomb in the code).

As I usually do, I started easy -- which, in my case, means locating the 
decimal point with log10, and moving it around using pow(10.0, n).

'pow' is over 1kB!!  And it pulls in something called __pow_754, which 
is HUGE -- like, 5kB or something!  Eeek!  I mean -- the code worked, 
but without much room in the end.

So I'm un-powing my sprintf, shaking my head at the vicissitudes of free 
software, and (since it's a hobby project) thinking about processors 
with more memory space.

-- 

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

Do you need to implement control loops in software?
"Applied Control Theory for Embedded Systems" was written for you.
See details at http://www.wescottdesign.com/actfes/actfes.html
Tim Wescott wrote:
>I'm shaking the box, trying to get the software to settle enough to fit >into a 64kB memory space. > ... > (Sad story about non-infinite memory ensues) > ... > ... and ... thinking about processors >with more memory space.
Use the Forth, Tim, use the Forth! (only 80% kidding.) -- Roberto Waltman [ Please reply to the group, return address is invalid ]
On Mon, 21 Feb 2011 18:17:38 -0800, Tim Wescott <tim@seemywebsite.com>
wrote:

>I'm shaking the box, trying to get the software to settle enough to fit >into a 64kB memory space. This is made difficult by the fact that it's >a human-interface rich environment with a bit of extra fat contributed >by the fact that I'm writing in C++. > >This is for an application that worked just peachy-keen on a captive >vendor's tool set, but which is too big using gnu tools. It's to be >expected, I suppose. > >As soon as I saw all of the I/O junk in the map file I realized that >maybe I shouldn't be using sprintf (even if it _did_ fit before). So I >took it out, and rather than contort my code, I'm writing a replacement >for just the formats that I'm using (yes, I know, bomb in the code). > >As I usually do, I started easy -- which, in my case, means locating the >decimal point with log10, and moving it around using pow(10.0, n). > >'pow' is over 1kB!! And it pulls in something called __pow_754, which >is HUGE -- like, 5kB or something! Eeek! I mean -- the code worked, >but without much room in the end. > >So I'm un-powing my sprintf, shaking my head at the vicissitudes of free >software, and (since it's a hobby project) thinking about processors >with more memory space. > >-- > >Tim Wescott >Wescott Design Services >http://www.wescottdesign.com
And I thought this thread was going to be about Alzheimer's or CRS disease or something. Eric Jacobsen http://www.ericjacobsen.org http://www.dsprelated.com/blogs-1//Eric_Jacobsen.php
On 22/02/2011 03:17, Tim Wescott wrote:
> I'm shaking the box, trying to get the software to settle enough to fit > into a 64kB memory space. This is made difficult by the fact that it's a > human-interface rich environment with a bit of extra fat contributed by > the fact that I'm writing in C++. >
C++ doesn't necessarily add fat - it depends on how you use it. If you've got exceptions and RTTI enabled, expect code to be bigger and slower. If you use the STL, expect code to be a /lot/ bigger. If you use a lot of virtual stuff, it may be a lot bigger (depending on the processor) - but it may be smaller than alternative C-style solutions to the same issues (such as with explicit function pointers). But generally speaking, beware libraries - whether C or C++ - they are often the cause of extra code space (and wasted run time).
> This is for an application that worked just peachy-keen on a captive > vendor's tool set, but which is too big using gnu tools. It's to be > expected, I suppose. >
You /expect/ that the gnu tools should make your code much bigger? There are some targets for which there are proprietary tools that are much better than open source alternatives. But on most major gcc targets, the compiler is on a par with the commercial tools in terms of code size and space. Sure, there will be some variation - but not as large as you are implying here. So what is the target? And what are the libraries? From your post, it looks like the libraries are your main issue - and here there can be a lot bigger differences. And what about tool versions? Where did you get them? There a lot of websites offering downloads of embedded gcc toolchains that are many years out of date. And how are you using the tools? Are you using appropriate compiler flags? (The manual has lots of information there, but you can also ask here on c.a.e. or in mailing lists.) For example, for bigger targets, the floating point code will often be IEEE standard - because that's the C standard behaviour. But it means much bigger and slower code than if you ignore the possibility of NaNs and allow slightly loser rules about rounding, etc. You have to use the "-ffast-math" switch to get faster but non-IEEE behaviour - many commercial compilers work like that by default.
> As soon as I saw all of the I/O junk in the map file I realized that > maybe I shouldn't be using sprintf (even if it _did_ fit before). So I > took it out, and rather than contort my code, I'm writing a replacement > for just the formats that I'm using (yes, I know, bomb in the code). > > As I usually do, I started easy -- which, in my case, means locating the > decimal point with log10, and moving it around using pow(10.0, n). >
Are you trying to display floating point data with decimals? There are /much/ more efficient ways to do that than using log10! Let us know your real problem, rather than the issues you are having with your solution, and you can get better help.
> 'pow' is over 1kB!! And it pulls in something called __pow_754, which is > HUGE -- like, 5kB or something! Eeek! I mean -- the code worked, but > without much room in the end. >
This is a library issue. What you are seeing is a large general-purpose routine, rather than smaller and more specialised functions. By the name, it is probably the IEEE-754 version of the code and will work correctly even when given awkward data (i.e., it will generate the specified NaNs, etc.). It is probably also a double precision version, which might not be what you need. The can probably be mitigated to some extent by using -ffast-math, and by using float instead of double (if appropriate). But in the end, it might just be a design choice of the library - larger but more general functions are more efficient for larger programs but are less efficient for smaller code.
> So I'm un-powing my sprintf, shaking my head at the vicissitudes of free > software, and (since it's a hobby project) thinking about processors > with more memory space. >
A vast amount of embedded development is done using free software, but it is not always the best choice. /Exactly/ the same applies to commercial tools. You have to pick appropriate tools for the task in hand, and know how to use them effectively. And you have to have tools that suit you, and the way you work. For some people, they like the way particular commercial tools work, and can't get their heads round gcc - they see it as some sort of refugee from the DOS days. Other people find most commercial tools awkward and inconvenient compared to the streamlined ease and consistency of gcc - they see commercial IDEs as too much lipstick on a pig. It's a matter of viewpoint, habit, experience and personal preference. But no matter what tools you are using, you'll get on a lot better if you ask for help with your problems, and give specifics, rather than whining that a toolchain you got for free doesn't work in exactly the same way as a toolchain that costs a lot of money. mvh., David
David Brown wrote:

> But generally speaking, beware libraries - whether C or C++ - they are > often the cause of extra code space (and wasted run time).
One I used, I forget whether it was for AVR or ARM, used pow to do bit shifts. And somebody's delay routine brought in the floating-point package so they could take their parameter in seconds. Faced with that, one writes one's own, and one's problems go away. Mel.
On Feb 21, 9:17&#4294967295;pm, Tim Wescott <t...@seemywebsite.com> wrote:
> I'm shaking the box, trying to get the software to settle enough to fit > into a 64kB memory space. &#4294967295;This is made difficult by the fact that it's > a human-interface rich environment with a bit of extra fat contributed > by the fact that I'm writing in C++. > > This is for an application that worked just peachy-keen on a captive > vendor's tool set, but which is too big using gnu tools. &#4294967295;It's to be > expected, I suppose. > > As soon as I saw all of the I/O junk in the map file I realized that > maybe I shouldn't be using sprintf (even if it _did_ fit before). &#4294967295;So I > took it out, and rather than contort my code, I'm writing a replacement > for just the formats that I'm using (yes, I know, bomb in the code). > > As I usually do, I started easy -- which, in my case, means locating the > decimal point with log10, and moving it around using pow(10.0, n). > > 'pow' is over 1kB!! &#4294967295;And it pulls in something called __pow_754, which > is HUGE -- like, 5kB or something! &#4294967295;Eeek! &#4294967295;I mean -- the code worked, > but without much room in the end. > > So I'm un-powing my sprintf, shaking my head at the vicissitudes of free > software, and (since it's a hobby project) thinking about processors > with more memory space. > > -- > > Tim Wescott > Wescott Design Serviceshttp://www.wescottdesign.com > > Do you need to implement control loops in software? > "Applied Control Theory for Embedded Systems" was written for you. > See details athttp://www.wescottdesign.com/actfes/actfes.html
This sort of behavior is to be expected. pow() is a double-precision floating-point arbitrary power function. Such a feat doesn't come easy on an integer-only RISC processor (which I'm assuming you have). If you have plenty of free time to blow, try writing a better version (i.e. one that is more compact without destroying its performance). Then, you can contribute it back to the community! In all seriousness though, this is a common issue when writing embedded code. This is the reason why many toolset vendors will offer two stdio implementations: one that supports floating-point types and one that does not. The code required to handle all of the printf() features with floating-point types can be pretty large (I've seen printf() take > 20 KB of code space on an embedded processor), and many applications can get by without it. Are you actually using floats/ doubles in your program? Jason
In article <F5adnQliG8Megf7QnZ2dnUVZ_u-dnZ2d@web-ster.com>, 
tim@seemywebsite.com says...
> > I'm shaking the box, trying to get the software to settle enough to fit > into a 64kB memory space. This is made difficult by the fact that it's > a human-interface rich environment with a bit of extra fat contributed > by the fact that I'm writing in C++. > > This is for an application that worked just peachy-keen on a captive > vendor's tool set, but which is too big using gnu tools. It's to be > expected, I suppose. > > As soon as I saw all of the I/O junk in the map file I realized that > maybe I shouldn't be using sprintf (even if it _did_ fit before). So I > took it out, and rather than contort my code, I'm writing a replacement > for just the formats that I'm using (yes, I know, bomb in the code). > > As I usually do, I started easy -- which, in my case, means locating the > decimal point with log10, and moving it around using pow(10.0, n). > > 'pow' is over 1kB!! And it pulls in something called __pow_754, which > is HUGE -- like, 5kB or something! Eeek! I mean -- the code worked, > but without much room in the end. > > So I'm un-powing my sprintf, shaking my head at the vicissitudes of free > software, and (since it's a hobby project) thinking about processors > with more memory space.
Is one of the libraries you are using a vendor support library for the I/O? I have seen cases of libraries which are poorly structured project modules that bring in all modules and functions assuming you have the biggest device in the range. In one case setting a GPIO pin type on the smaller footprint devices loaded GPIO configuration routines for Ethernet, Can, USB, I2S and other things not present on that device. The support response was use "-g sections" linker option to remove uncalled functions. A using a linker trick to fudge the bad software structure. If you must support floating point and display floating point for any arbitrary range you will have issues with any form of [s}printf. My personal suggestion is consider if this range is ALWAYS limited or can be determined to have a floor and ceiling limit before doing the output conversion. This can greatly reduce the complexity of floating point representation. -- Paul Carpenter | paul@pcserviceselectronics.co.uk <http://www.pcserviceselectronics.co.uk/> PC Services <http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font <http://www.gnuh8.org.uk/> GNU H8 - compiler & Renesas H8/H8S/H8 Tiny <http://www.badweb.org.uk/> For those web sites you hate
On Feb 22, 4:17&#4294967295;am, Tim Wescott <t...@seemywebsite.com> wrote:
> > > 'pow' is over 1kB!! &#4294967295;And it pulls in something called __pow_754, which > is HUGE -- like, 5kB or something! &#4294967295;Eeek! &#4294967295;I mean -- the code worked, > but without much room in the end.
Just looked at my e^X, 2^x etc. FPU code which is part of DPS. For power (PPC), written in VPA, it is $1a0 (416 dec) bytes - double precision FP. Uses the FPU on the chip though (which has fmul, fadd, fsub, fdiv). On a CPU32 - done in 68k assembly - the code size is $232 (562 dec) bytes (no FPU to help, just the integer unit). I wonder if one is not using the HLL libraries and has to write his own ones, what good is the HLL for at all then... (other than staying with the trend, that is). Dimiter ------------------------------------------------------ Dimiter Popoff Transgalactic Instruments http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/sets/72157600228621276/
On 22/02/2011 15:06, Didi wrote:
> On Feb 22, 4:17 am, Tim Wescott<t...@seemywebsite.com> wrote: >> >> >> 'pow' is over 1kB!! And it pulls in something called __pow_754, which >> is HUGE -- like, 5kB or something! Eeek! I mean -- the code worked, >> but without much room in the end. > > Just looked at my e^X, 2^x etc. FPU code which is part of DPS. > For power (PPC), written in VPA, it is $1a0 (416 dec) bytes - double > precision > FP. Uses the FPU on the chip though (which has fmul, fadd, fsub, > fdiv). > > On a CPU32 - done in 68k assembly - the code size is $232 (562 dec) > bytes > (no FPU to help, just the integer unit). > > I wonder if one is not using the HLL libraries and has to write his > own ones, what good is the HLL for at all then... (other than staying > with the trend, that is). >
For embedded programming, you use /some/ HLL libraries - but not others. For example, it is common to use the libm libraries directly if you need them - but you do so only if you need it, and you do so appropriately. So if you are using an 8-bit AVR, it is very rare that you would use floats rather than integers - and even rarer that you would use doubles rather than floats. But if you /do/ need to use them, then you do so using the libraries. Other libraries are less useful in embedded systems - there is little in stdio.h that makes sense in most cases, and the *printf family is always very expensive in size and time. Many libraries for embedded toolchains come with a variety of *printf functions to give a better compromise between functionality and size. In the end, however, it comes down to a balance between the size and speed of the embedded system, and the cost and speed of the development. Sometimes it makes sense to use inefficient libraries that are easily available, rather than finding or writing something better. But you should only do so when you know what you are doing - this thread started with someone who appears to have thrown code at the toolchain without understanding the compiler or the library.
In comp.dsp Jason <cincydsp@gmail.com> wrote:
(snip)

>> 'pow' is over 1kB!! &#4294967295;And it pulls in something called __pow_754, which >> is HUGE -- like, 5kB or something! &#4294967295;Eeek! &#4294967295;I mean -- the code worked, >> but without much room in the end.
(snip)
> This sort of behavior is to be expected. pow() is a double-precision > floating-point arbitrary power function. Such a feat doesn't come easy > on an integer-only RISC processor (which I'm assuming you have). If > you have plenty of free time to blow, try writing a better version > (i.e. one that is more compact without destroying its performance). > Then, you can contribute it back to the community!
Since about when I learned C (before ANSI C), I have thought the lack of integer power functions a mistake in C. There should be functions for both integer to integer power, and double to integer power. Optimizing compilers would also optimize small integer powers. Oh well. -- glen