EmbeddedRelated.com
Forums
Memfault Beyond the Launch

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=A0pm, 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. =A0This 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. =A0It'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). =A0So 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!! =A0And it pulls in something called __pow_754, which > is HUGE -- like, 5kB or something! =A0Eeek! =A0I 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
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++. > > 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. >
One of the reasons I never use standard c lib functions much is the amount of crud they tend to pull in, and much of it seems to use signed types where unsigned would be more appropriate. Memories of printf() that pulls in over 100k, just to print a formatted string. Fine if it's running on a desktop machine, but useless for most embedded work. Same applies to the lib. Organising the data appropriately so you can do scaled integer math does help, or designing your own simplified format and limited range floating point functions to suit the application, where that needs to be externalised. It's not too difficult to roll your own as needed and build libraries over a few projects, with the added advantage that you always have full visibility of all the code in the system... Regards, Chris
ChrisQ wrote:

> applies to the lib. Organising the data appropriately so you can do
^^^ Sorry, should say math lib...
On 22/02/2011 13:19, Mel wrote:
> 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.
That sounds /very/ strange. Bit shifts are integer operations, while pow is a floating point function - they should not be mixed unless your source code says they must be mixed. I'm not going to claim that gcc for the AVR and the ARM are bug-free, or that they always generates optimal code. But this sounds so weird that I'd want to see details before accepting it.
> 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. >
Yes, there is lots of poor or inefficient code out there - I've seen floating point code used in delay routines like that. Done properly, you arrange for the floating point calculations to be done for accuracy and convenience, but evaluated at compile-time rather than run-time. However, that requires that both the programmer and the compiler do the right thing...

Memfault Beyond the Launch