EmbeddedRelated.com
Forums

And -- pow! My memory was gone.

Started by Tim Wescott February 21, 2011
Tim Wescott wrote:
> 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).
Do you really need that? For most floating-point display code I do, nobody needs exponential format. And for "handy" numbers, one can do a simple, slow, probably totally standards-violating but short float max = 1.0; while (max < value) max *= 10; while (max > 1.0) { max /= 10; int n = 0; while (value >= max) { ++n; value -= max; } putchar('0' + n); } Make the while loop a little longer for fractional output. Even if you need exponential format, the decimal point can be located without log10. int exp2, exp10; frexp(c, &exp2); exp10 = exp2 * 19728L / 65536; // 65536/19728 \approx log_2 10 frexp just dissects floating point representation. The result may be one off, which can be easily corrected (if, after moving the decimal point, the result is >= 10.0). pow(10.0, n) for integral n can be done with a loop instead of a log/exp pair.
> '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.
At that point, I'd go hunting for a switch "link with non-IEEE-754 floating point libraries". Stefan
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
On 02/22/2011 12:15 AM, David Brown wrote:
> 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).
There seems to be about 3-4kB of stuff that's specifically associated with C++, starting with malloc (which I know _I'm_ not using) and going from there.
>> 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?
Cortex M3
> 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.
Newlib.
> 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.
gcc 4.5.2 -- is that too out of date? Maybe there's a beta version that I should be using? This is a fresh build using the "summon-arm-toolchain" script that seems to be one's best bet for getting something that'll work on the Cortex M3.
> 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.
I will look into the -ffast-math switch. Hopefully I can use it without rebuilding the libraries, but I can do that, too.
>> 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.
I _know_ there's more efficient ways! Like I said -- I started out with 'easy', and planned on working from there.
>> '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.
Obviously.
> 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.
Ayup. And I'm not terribly inclined to rewrite the library, so will probably go with working around the problems.
>> 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.
Well yes. In this case, the 'different bucket' principal applies -- one's budget for profit-generating work has a few more zeros at the end than one's budget for playing around.
> 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.
I vastly prefer the command-line tool approach. If I can't go to a command line and type 'make' to kick things off, then I haven't finished the job yet. Using an IDE to do your thinking for you is just an invitation to broken code in a month or two, and an endless life of never knowing if you've gotten all of the critical files archived.
> 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.
Mostly I was sharing my amazement about how much of a chunk one (supposedly) itty bitty mathematical function took up, and how much more space the gnu embedded library for the ARM takes up than the alternative, commercial, tool. (With the library sprintf, the thing compiles to something like 78kB, which is a barrier to progress given that the processor in question only has 64kB of flash). I do appreciate your suggestion about -ffastmath. -- 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
On 02/22/2011 05:05 AM, Paul wrote:
> 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.
I never use those. My impression of them is that they're written by zit-faced kids in India who aren't good enough to get jobs writing software for spammers. Even if they get you half way through a project, at some point before you're done they bite you.
> 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.
I know that, but I also know that there was a software vendor library (it has to be either Keil or IAR -- I think IAR) that's much smaller.
> 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.
Yup. -- 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
On 02/22/2011 12:15 AM, David Brown wrote:
> 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
Come to think of it, I vaguely remember putting 'sprintf' in as a placeholder with the original tool chain, and being rather surprised when things actually linked. Now I need to dig out the old Windows machine, and see what was on there... -- 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
On 2011-02-22, Tim Wescott <tim@seemywebsite.com> wrote:

> Mostly I was sharing my amazement about how much of a chunk one > (supposedly) itty bitty mathematical function took up, and how much > more space the gnu embedded library for the ARM
What is "the Gnu embedded library for the ARM"? I can think of probably a half-dozen different "libc" implimentations I've used with gcc. Which one are you using?
> takes up than the alternative, commercial, tool. (With the library > sprintf, the thing compiles to something like 78kB, which is a > barrier to progress given that the processor in question only has > 64kB of flash). > > I do appreciate your suggestion about -ffastmath.
If you're using glibc and hoping for something not-huge, you're going to be pretty frustrated. uClibc and newlib are less huge and still pretty full-featured. There are others that are smaller-still, but they often tend to be specific to a particular architecture, and lack some features (e.g. they may not provide any of the calls that use the heap). -- Grant Edwards grant.b.edwards Yow! BELA LUGOSI is my at co-pilot ... gmail.com
On 02/22/2011 08:05 PM, Tim Wescott wrote:

> Mostly I was sharing my amazement about how much of a chunk one > (supposedly) itty bitty mathematical function took up, and how much more > space the gnu embedded library for the ARM takes up than the > alternative, commercial, tool. (With the library sprintf, the thing > compiles to something like 78kB, which is a barrier to progress given > that the processor in question only has 64kB of flash).
It makes sense, though. GCC has a large number of target architectures, and therefore these libraries have been written in C to make them easier to port. Commercial tools are usually aimed towards a single target, which makes it a lot easier to hand optimize the math libs in assembly.
On Tue, 22 Feb 2011 11:05:49 -0800, Tim Wescott <tim@seemywebsite.com>
wrote:

>> But generally speaking, beware libraries - whether C or C++ - they are >> often the cause of extra code space (and wasted run time). > >There seems to be about 3-4kB of stuff that's specifically associated >with C++, starting with malloc (which I know _I'm_ not using) and going >from there.
1st: Be sure to set -fno-exceptions -fno-rtti ! 2nd: Check the map-file who pulls in malloc. If you use sprintf, there you are. 3rd: Get the sprintf() out of the newlib sources and make a local copy where you remove the un-needed stuff.
>gcc 4.5.2 -- is that too out of date? Maybe there's a beta version that >I should be using?
Using the latest build might not always lead to the best results. Did you try e.g. CodeSourcery ?
>I will look into the -ffast-math switch. Hopefully I can use it without >rebuilding the libraries, but I can do that, too.
That'll won't improve the code size. This switch only tells GCC to be a bit less strict w.r.t. IEEE754 -- 42Bastian Do not email to bastian42@yahoo.com, it's a spam-only account :-) Use <same-name>@monlynx.de instead !
On Mon, 21 Feb 2011 18:17:38 -0800, Tim Wescott <tim@seemywebsite.com>
wrote:

>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).
Table ! Table ! Table ! Are you using float or double ? What is the range for <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.
Ok. Do the math: 1KB => table for pow(10,0) .. pow(10,255) -- 42Bastian Do not email to bastian42@yahoo.com, it's a spam-only account :-) Use <same-name>@monlynx.de instead !
On 02/22/2011 09:17 PM, 42Bastian Schick wrote:
> On Mon, 21 Feb 2011 18:17:38 -0800, Tim Wescott<tim@seemywebsite.com> > wrote: > >> 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). > > Table ! Table ! Table ! > > Are you using float or double ? > > What is the range for<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. > > Ok. Do the math: 1KB => table for pow(10,0) .. pow(10,255) >
Or just multiply by 10 in a loop.