will using functions add to memory ? - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 03:22:54 pm
content: Will using functions for portions of my code add to the program memory usage (if called once only)? my understanding of functions is that the contents of the function just replaces the function call. so basically assuming i use a function once only will calling the function use more program memory than putting the functions code straight into the program ?

author: madires
author_rank: Super Contributor
timestamp: May 18, 2014, 03:54:10 pm
content: Quote from: Simon on May 18, 2014, 03:22:54 pmYes, it will increase the stack usage. When the function is called it will save some registers to the stack (push), i.e. the registers which are used locally in the function. Before returning, the function restores the used registers by retrieving them from the stack (pop). Also the program counter has to be tracked for each function call (stored in the stack again) and function parameters might also be pushed to the stack.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 04:00:49 pm
content: By stack do you mean ram ? or the general purpose registers ?, I mean is it much to be concerned about ?

author: mariush
author_rank: Super Contributor
timestamp: May 18, 2014, 04:03:31 pm
content: I would say it depends on the compiler, how well it optimizes the source code.I have right now a project open that uses XC8 1.31 free, and there is a function that's called only once in the main() function and looking at the disassembly, the compiler simply does a call to the address where the function is, instead of just adding its assembly inside the main() assembly code. So it's about 4 cycles lost (at 16 mhz clock, that's about 1us of wasted time) for the call and return... and about 3 bytes of extra flash memory usage.Maybe XC8 pro optimizes it, I don't know.

author: madires
author_rank: Super Contributor
timestamp: May 18, 2014, 04:14:20 pm
content: Quote from: Simon on May 18, 2014, 04:00:49 pmYes, RAM. The stack is located in the RAM. If you exceed the maximum stack size you'll probably overwrite variables stored in RAM but a good compiler should warn you if it knows about the memory constraints.https://mbed.org/handbook/Memory-Modelhas some nice pictures explaining how the memory space is divided.

author: John Coloccia
author_rank: Super Contributor
timestamp: May 18, 2014, 04:19:01 pm
content: Quote from: Simon on May 18, 2014, 04:00:49 pmWhen you call a function, it needs to store where the call came from (so it can go back when it's done), parameters and local variables that the function uses (must be stored each time or the function could never be re-entrant) and whatever value is returned. This all traditionally gets stored in the "stack", which is generally just a portion of RAM that's been allocated for stack space. Of course, the compiler is always free to do what it wants, but that's generally the case.Even if you run out of stack space, it's generally just a matter of increasing it in the compiler options. Unless you have a reason to worry about it, I wouldn't worry about it.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 04:31:36 pm
content: ok doesn't sound like too much of a problem, I'm at 3% of RAM and I can certainly loose 3 bytes

author: zapta
author_rank: Super Contributor
timestamp: May 18, 2014, 04:46:46 pm
content: Lookup the 'inline' keyword. If a function or method called once it should not increase the ran or flash size.Sent from my Nexus 5 using Tapatalk

author: zapta
author_rank: Super Contributor
timestamp: May 18, 2014, 04:47:51 pm
content: Duplicate. Deleted.

author: tjaeger
author_rank: Regular Contributor
timestamp: May 18, 2014, 07:07:47 pm
content: Usually it's enough to declare the function as static, this way the compiler knows the function is only used once and will inline it automatically.

author: Simon
author_rank: Unknown
timestamp: May 18, 2014, 07:16:52 pm
content: how do I do that ?

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 07:56:42 pm
content: Put static in front of it , and remember to pre declare it in the top.And maybe even tell avrgcc to inline the function.static inline uint8_t myfunc(void); //predeclarestatic inline uint8_t myfunc(void){......}Note that static means that it can only be seen/called within the ".c file" it is declared in , as it will NOT generate a "global" symbol for the linker.If you call the function several times , the compiler will try to inline it every time , meaning larger code/Bingo

author: tjaeger
author_rank: Regular Contributor
timestamp: May 18, 2014, 08:26:11 pm
content: Quote from: bingo600 on May 18, 2014, 07:56:42 pmIt's generally better to leave the decision on whether or not to inline the function up to the compiler. Unless maybe the function is used in a really tight loop or an ISR.

author: bingo600
author_rank: Super Contributor
timestamp: May 18, 2014, 09:08:17 pm
content: Quote from: tjaeger on May 18, 2014, 08:26:11 pmWho would inline a function if it wasn't tight code/Bingo

author: John Coloccia
author_rank: Super Contributor
timestamp: May 18, 2014, 09:10:36 pm
content: Quote from: tjaeger on May 18, 2014, 08:26:11 pmBingo. Compilers generally do a much better job of optimizing code than programmers do. The exception to this is DSPs with strange instruction sets, cache management, memory alignment requirements, etc. Then you really have to know exactly what you're doing or you will botch things up royally. Also, it pays to know how your specific processor's memory management and cache management work if you want to get every drop of performance out of a piece of code. I've done a lot of real time coding, and processing is RARELY the problem. Nearly every problem ends up being I/O bound and you're always coming up against issues such as flushing the pipeline, caching the wrong data, etc etc etc. That's where the money is. The compiler does a fine job on it's own of figuring out how to handle mundane tasks such as function calls, loop unrolling, inlining and things like that.Let me give you an example. Which of these will run faster, assuming no additional optimization:for (i=0; i<SOME_NUMBER; i++){Do_Something(i);}or{i=0UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++UnRolled;DoSomething;i++}Most people still say the second way is obviously faster, but most of the time the first way actually has the advantage because it's quite likely that DoSomething() will be sitting in the instruction cache after the first call and the rest will execute blazingly fast, whereas the second way forces a bunch more memory to be read in...which is SLOOOOOOWWWWWWW. Also, churning on "localized" memory and spitting the results out at the end, as opposed to working on scattered memory...same thing. Intelligent memory management is where you get truly huge gains, and compilers are very poor at this because while they can optimize instructions very well, they're very poor at figuring out your semantics. How does it know what's OK and what's not? It generally doesn't and can't take full advantage of the architecture without intelligent layout from the designer to show the way.

author: Marco
author_rank: Super Contributor
timestamp: May 18, 2014, 09:44:11 pm
content: If all was right in the world we would never even have to unroll code. But no ... x86 and ARM processor designers would rather blow vast amounts of hardware on branch prediction which is still guaranteed to get it wrong at least once in the loop rather than introduce/support instructions for zero overhead looping.

author: hamster_nz
author_rank: Super Contributor
timestamp: May 18, 2014, 10:19:39 pm
content: Quote from: Marco on May 18, 2014, 09:44:11 pmYou must be a software person... :-)Pipelining is essential for the CPU to have the data it wants, where it wants it, when it wants it. Fetching a register takes a cycle 0.3ns, adding two numbers takes a cycle 0.3ns. storing a value into a register takes 0.3ns, all of which is hidden from the programmer.I'm happy with my 3GHz CPU, even if an 64-bit IDIV takes 96 cycles

author: PeterG
author_rank: Frequent Contributor
timestamp: May 18, 2014, 11:30:41 pm
content: Simon, you may find the following 2 videos helpfull regarding 'Stacks'.

author: Harvs
author_rank: Super Contributor
timestamp: May 19, 2014, 12:01:36 am
content: Whilst it's good to be thinking about, until you actually hit issues of running out of resources or performance not meeting requirements, making clean, easily debugged and reusable code is more important.In other words, if you're code is going to be more readable by extracting the function, do it.

author: Bassman59
author_rank: Super Contributor
timestamp: May 19, 2014, 01:36:00 am
content: Quote from: tjaeger on May 18, 2014, 07:07:47 pmDeclaring a function asstaticdoesn't tell the compiler that it's used only once and therefore can be inlined.Astaticfunction has internal, that is, file-scope, linkage; as such it is not visible outside of the file in which it is declared. Astaticfunctionfoo()declared in one source file will be considered by the linker a totally different animal from astaticfunctionfoo()declared in another source file.If you want the compiler to consider inlining a function, use theinlinekeyword.

author: Marco
author_rank: Super Contributor
timestamp: May 19, 2014, 01:46:40 am
content: Quote from: hamster_nz on May 18, 2014, 10:19:39 pmA branch mispredict takes 6, that's why we sometimes still have to unroll. There is no inherent conflict between pipelining and zero overhead looping (or code loadable BTBs like Cell has for that matter).I didn't mean to present it as an either/or situation ... I meant that they rather throw more hardware at branch prediction for diminishing returns than create instructions and spend the tiny amount of hardware necessary for these kinds of corner cases which branch prediction can fundamentally not get right (until it becomes data dependent, but that will take a whole lot more hardware).

author: John Coloccia
author_rank: Super Contributor
timestamp: May 19, 2014, 02:10:18 am
content: Marco, if they built x86 chips like DSPs, what would happen is caching and memory management would become very predictable, and only .01% of programmers would have a clue what the hell is going on and you'd have code that would grind to a halt on the fastest of processors......and everyone would scratch their head trying to figure out why the latest Intel Ultium chip (or whatever the hell they're calling it these days) doesn't work worth a damn.There's a reason that competent engineers get payed well to do embedded and real-time design. It's not easy, and it's not the same skill set as cobbling together an accounting package.Anyhow, any compiler worth a damn will unroll ENOUGH to satisfy getting the code optimally stuffed into the cache. It's not always a matter of unroll or don't unroll. Sometimes, you unroll a little bit and loop over that. Processor optimization is a very tricky business. I've done plenty of it by hand, plenty of it just letting the compiler go on it's own, and the best is always a mix of optimizing the I/O based on architecture and allowing the compiler to optimize the actual instructions.

author: IanB
author_rank: Super Contributor
timestamp: May 19, 2014, 02:35:23 am
content: Quote from: Simon on May 18, 2014, 03:22:54 pmA good principle to live by is that computer programs should be written for the benefit of human readers, so that programmers can readily understand what they are supposed to do and can easily modify them.Subroutines usually make the code easier to understand, therefore subroutines are usually a good idea.The time to worry about the potential overhead of subroutines in memory or performance is when (if ever) memory or performance become limiting. If you don't hit the limits it is better to write more maintainable code. And if you do hit the limits it may be better to upgrade the hardware than to spend time messing with the code to fit a quart into a pint pot.

author: Marco
author_rank: Super Contributor
timestamp: May 19, 2014, 03:28:20 am
content: Quote from: John Coloccia on May 19, 2014, 02:10:18 amIt's not an either/or situation, take Cells solution to just let you load an address in the BTB ... the ability to do that doesn't remove the ability of the branch predictor to do it when you don't.

author: John Coloccia
author_rank: Super Contributor
timestamp: May 19, 2014, 03:39:49 am
content: Quote from: Marco on May 19, 2014, 03:28:20 amYeah, that's a valid point. A lot of mainstream processors really could do a much better job of giving aware programmers, and maybe aware compilers, a fighting chance of getting some sort of higher performance out of them.Or at least predictable performance.And it always always always (nearly always) comes back to nearly everything in the high performance world being I/O bound.The more control we have over memory and cache management, the easier it is for the guy who's really trying to squeeze performance out of a system.

author: Mechatrommer
author_rank: Super Contributor
timestamp: May 19, 2014, 03:55:16 am
content: Quote from: John Coloccia on May 18, 2014, 09:10:36 pminline (or static) is just like the rest of keywords in C, you use it when you need it, or you use it when you know what you are doing. i will call a compiler a stupid compiler if i put the word "inline" when with its infinite wisdom of stupidity opts not to inline it.

author: andersm
author_rank: Super Contributor
timestamp: May 19, 2014, 04:29:25 am
content: Quote from: Bassman59 on May 19, 2014, 01:36:00 amOf course it doesn't, but if the compiler has to generate an outline copy it is less likely to inline it, unless it's trivial.

author: Jeroen3
author_rank: Super Contributor
timestamp: May 19, 2014, 08:13:36 am
content: Relying on the compiler to make code fast is bad. Since programming languages are designed to be portable you can get issues when you take your modules to another platform.Also, you want to be able to debug (step through) your code. With -Omax this is almost impossible.Code should be fast and debuggable.(is that a word?)Best thing to do is make everything as explicit as possible and leave the implicit behavior to a minimum. If you intend to use a functions as inline, don't rely on the compilers -O flags, but use the proper keywords. This way it is obvious to any reader reading the code while not having to read any assembler or mapping output. And most of all, resistant to compiler updates.Sure you will use some of the compilers optimization, otherwise C would translate awful. But inline, static or const should hint the compiler on what you are trying to achieve.

author: amyk
author_rank: Super Contributor
timestamp: May 19, 2014, 12:26:18 pm
content: Quote from: Marco on May 18, 2014, 09:44:11 pmx86 has had LOOP/LOOPNZ(E) since the beginning, Intel currently doesn't optimise it but it's there and in the future maybe they'll make use of it.

author: John Coloccia
author_rank: Super Contributor
timestamp: May 19, 2014, 02:03:32 pm
content: Quote from: Jeroen3 on May 19, 2014, 08:13:36 amThis is complete nonsense. Portability is a strong argument FOR compiler optimization, not against. Or maybe you'd rather write your program 5 times rather than just recompile it 5 times?As far as stepping through with a debugger, this is about as far down on the list of concerns as it can get. Especially in the embedded world, most of us just pull up our big boy pants and don't use the debugger anyhow. It's usually easier, faster and certainly for in circuit hardware a lot less trouble to simply use some debug statements....or even just stare at the code for a few seconds.

author: macboy
author_rank: Super Contributor
timestamp: May 20, 2014, 01:05:20 pm
content: Quote from: Simon on May 18, 2014, 03:22:54 pmDeclare your function as static inline, and then you are assured that the function will not be "called" but that the equivalent code will be put in place of the (and every) function call. If you call your function in only one or two places, this usually reduces code size, increases execution speed, reduces stack usage. If you call it in many places, it can increase code size a lot (or it can actually decrease code size, if the function is very simple).If you just use inline but not static inline, then the compiler will still generate the inline code where it makes sense to, but will also (likely) generate a callable version of the function for linkage in other files. This increases code size, so you don't call the function from elsewhere, use static.Inline is tricky; the compiler needs to know the definition (not just declaration) of the function prior to it being called. So the definition must come higher up in the file than the first usage of that function, or the compiler can't inline those earlier calls to it.

author: dannyf
author_rank: Super Contributor
timestamp: May 20, 2014, 01:48:33 pm
content: QuoteBingo! Absolutely right.I am still waiting for someone to extern a static type,

author: zapta
author_rank: Super Contributor
timestamp: May 20, 2014, 02:10:44 pm
content: Using static for internal functions is a good practice, regardless of inline, it's limits the scope of the fiction. Also inline can be used with non static functions, for example when the function is in a .h file. And last but not least, inline can reduce size also for simple functions that are called multiple times because it eliminate the function call sequence.Sent from my Nexus 5 using Tapatalk

author: HackedFridgeMagnet
author_rank: Super Contributor
timestamp: May 20, 2014, 02:49:41 pm
content: Quote from: Jeroen3 on May 19, 2014, 08:13:36 amQuote from: John Coloccia on May 19, 2014, 02:03:32 pmI am pretty sure you misunderstood him, its not complete nonsense. and hardly a fair analogy.Quote from: John Coloccia on May 19, 2014, 02:03:32 pmSome of us (don't know the numbers) like using a debugger in preference to debug statements, I just want to check that those pants of yours aren't so high that they are blocking the view.

author: andersm
author_rank: Super Contributor
timestamp: May 20, 2014, 03:09:53 pm
content: Quote from: HackedFridgeMagnet on May 20, 2014, 02:49:41 pmIf you have to resort to debugging, you have already lost. Preventative measures, such as unit tests, simulation and code analysis are better than any debugger.

author: zapta
author_rank: Super Contributor
timestamp: May 20, 2014, 03:50:42 pm
content: Quote from: andersm on May 20, 2014, 03:09:53 pm'Lost' is a big word. There is more than one way to skin a cat.

author: tjaeger
author_rank: Regular Contributor
timestamp: May 20, 2014, 04:10:06 pm
content: Quote from: dannyf on May 20, 2014, 01:48:33 pmIf a static function is used once in a compilation unit, then the compiler can be sure that it is used only once, so it will inline it even at the most modest of optimization settings. Why is this so hard to comprehend?

author: John Coloccia
author_rank: Super Contributor
timestamp: May 20, 2014, 04:34:23 pm
content: It also allows the compiler to do other optimizations that it would normally not be able to do, both outside and inside the function itself. Anyhow, it's just good practice not to clutter up the global namespace unless something really is globally needed.re: debugging and stuffCommon practice...and GOOD practice....is to log just about everything and to have multiple log levels that you can turn on and off....or even compile out of your code entirely. Yes, it takes upfront work to build such a thing, but once it's built you take it from project to project and just make minor tweaks to be compatible with the various platforms. Maybe one goes to a serial port...maybe one goes to a file...or to IDE's console. It's such a pleasure to have a bug come in from 5000 miles away, with the zipped up logs, and to be able to immediately see exactly what the problem is.On one project, when I was a wee lad programmer, they released the code with debug symbols built in. I used that trick over and over in my career. What you do is implement a stack-walker in the global exception handler and using the debug information not only can you log the entire chain of calls, but you can get the exact value of all of your local variables, and you get the exact line numbers the calls were made from, including the exact line number that caused the exception. Talk about a powerful tool!Anyhow, that's usually a lot more useful than the typically crappy, command line debugger nonsense that come with so many environments.

author: HackedFridgeMagnet
author_rank: Super Contributor
timestamp: May 20, 2014, 11:27:19 pm
content: QuoteI think the logic of that statement is flawed.QuoteI think the logic of that statement is flawed.I think people who pride themselves on programming should be careful to write arguments that make logical sense. Just putting some qualification around these bald statements sometimes does the trick.eg.Code:"I have never found a use for a debugger, so I can't understand why anyone would use one".

author: andersm
author_rank: Super Contributor
timestamp: May 21, 2014, 04:56:11 am
content: Quote from: HackedFridgeMagnet on May 20, 2014, 11:27:19 pmThe cost of fixing an error goes up the more time passes between when it's introduced and when it's discovered. Not introducing bugs in the first place is the cheapest option, which is the goal of methodologies like test-driven development. Simply put, if you're spending a lot of time in the debugger, something is not right.

author: Mechatrommer
author_rank: Super Contributor
timestamp: May 21, 2014, 05:09:00 am
content: narrowmind will think debugging process is just "the debugger" or they probably "lost". anything said which meant to improve code func and flawlessness are debugging processes or techniques. give some thinking of what it takes, how much time needed to unit test a chunk of subroutine, or eyeballing it, analyzing etc anything for that sake. wont we need to debug the unit tester? imho of my 2cnts.

author: Jeroen3
author_rank: Super Contributor
timestamp: May 21, 2014, 01:02:46 pm
content: Some bugs, however unlikely, might be caused by flaws in your tools. I've seen it twice already.Once with ATtiny, which took ages to find since there is no code stepping capability or debug at all.The entire chip must be considered as black box. You're doomed to follow read the assembler yourself.And once with Keil, which was easier to solve since you could analyse the compiled code by stepping it, viewing all the registers and find that it translated an if wrong somewhere.

author: westfw
author_rank: Super Contributor
timestamp: May 22, 2014, 08:15:02 am
content: QuoteYou didn't find the simulator useful? (but OMG, if the simulator has bugs!)Quote from: Simon on May 18, 2014, 03:22:54 pmgetting back to the original question: In general, even without any fancy optimizations, the amount of code and RAM use added by using functions vs inline code is small, and the benefits of using functions (in terms of clarity, debugability, modularity, re-usability, and other factors) are relatively large, so that using functions is considered a good practice, even when they are called only once.

author: ejeffrey
author_rank: Super Contributor
timestamp: May 22, 2014, 08:19:48 pm
content: Quote from: andersm on May 21, 2014, 04:56:11 amWhen you detect and when you fix a bug has zero relevance to the value of a debugger. What you mean is that you don't understand debuggers, don't know how to use them, and have never found them valuable. Which is fine, but saying "You shouldn't use/have to use a debugger" is just parochial nonsense generalizing a tiny bit of your experience to a world you don't understand.