Optimizations - Programmer vs. Compiler?
Saravana Kannan asks: "I have been coding in C for a while (10 yrs or so) and tend to use short code snippets. As a simple example, take 'if (!ptr)' instead of 'if (ptr==NULL)'. The reason someone might use the former code snippet is because they believe it would result in smaller machine code if the compiler does not do optimizations or is not smart enough to optimize the particular code snippet. IMHO the latter code snippet is clearer than the former, and I would use it in my code if I know for sure that the compiler will optimize it and produce machine code equivalent to the former code snippet. The previous example was easy. What about code that is more complex? Now that compilers have matured over years and have had many improvements, I ask the Slashdot crowd, what they believe the compiler can be trusted to optimize and what must be hand optimized?"
"How would your answer differ (in terms of the level of trust on the compiler) if I'm talking about compilers for Desktops vs. Embedded systems? Compilers for which of the following platforms do you think is more optimized at present - Desktops (because is more commonly used) or Embedded systems (because of need for maximum optimization)? Would be better if you could stick to free (as in beer) and Open Source compilers. Give examples of code optimizations that you think the compiler can/can't be trusted to do."
Programmer: Hey, compiler. How do you like optimizing?
Compiler: Optimizing? Optimizing? Don't talk to me about optimizing. Here I am, brain the size of a planet, and they've got me optimizing inane snippets of code. Just when you think code couldn't possibly get any worse, it suddenly does. Oh look, a null pointer. I suppose you'll want to see the assembly now. Do you want me to go into an infinite loop or throw an exception right where I'm standing?
Programmer: Yeah, just show me the stack trace, won't you compiler?
A programmer is a machine for converting coffee into code.
You MUST trust the compiler more and more to protect the code from buffer overflows and other trivial, but hard-for-humans-to-detect mistakes.
I think writing clear and easy to understand code is more important in the long run, especially if other people will have to look at it.
Optimize. Using cryptic, short variable names also shaves valuable microseconds off compile time and run time.
Donald Knuth wrote "We should forget about small efficiencies, about 97% of the time. Premature optimization is the root of all evil."
The sad truth is that, as far as optimization goes, this isn't where attention is most needed.
Before we start worrying about things like saving two cycles here and there, we need to start teaching people how to select the proper algorithm for the task at hand.
There are too many programmers who spend hours turning their code into unreadable mush for the sake of squeezing a few milliseconds out of a loop that runs on the order of O(n!) or O(2^n).
For 99% of the coders out there, all that needs to be known about code optimization is: pick the right algorithms! Couple this with readable code, and you'll have a program that runs several thousand times faster than it'll ever need to and is easy to maintain--and that's probably all you'll ever need.
Obliteracy: Words with explosions
if(!ptr) is equivalent to if(ptr == 0)
The problem is that there is nothing that says that NULL must be 0. Potentially, one could define NULL to be something else - like -1. Therefore, one should always use if(ptr == NULL).
"Honey, it's not working out; I think we should make our relationship open-source."
Prepare for 93242.5 posts telling you to use java or perl or ada instead.
Free Mac Mini Yeah, it's
I trust the compiler to optimize almost everything. Use a profiler, since hand optimized code is more difficult to code correctly and more difficult to maintain you should only do it when it matters.
[Set Cain on fire and steal his lute.]
It's better to write clear, legible code that saves a human minutes of reading, than complex code that might save a computer a few milliseconds of processing time per year, because human time costs more than machine time.
Also the clear code will result in fewer misinterpretations, which will mean fewer bugs (especially when the original author is not the one doing maintenance years later), further reducing costs in dollars, man hours, and frustration.
Who compiles code anymore? Between Perl, PHP and Shell, I get everything done that I need too!
Aren't there machines out there where the C compiler specifically defines NULL as value that is not equal to 0? I recall reading that somewhere, and that was my reason for using ==NULL instead of !. My C days are long gone though...
Wenn ist das Nunstueck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput.
The compiler will always produce asm better than a human, but you have to remember - GIGO (garbage in, garbage out).
Make the code EASY to read and logical... 5 lines is better than trying to get it in 1 line - the compiler will still produce the same end product, anyway.
There really is no one answer to this, as it depends on the compiler itself, and the target architecture. The only real way to be sure is to profile the code, and to study assembler output. Even then, modern CPUs are really complicated due to pipelining, multilevel cache, multiple execution units, etc. I try not to worry about micro-twiddling, and work on optimizations at a higher-level.
(S(SKK)(SKK))(S(SKK)(SKK))
I just checked the U.S. Patent office and sure enough, just minutes after your post, Microsoft patented "if (!ptr)" as a shorthand for "if (ptr==NULL)".
Prepare to be sued.
"What the hell is an aluminum falcon?"
Hard to measure, but what is the tradeoff between increased speed and increased readability (which is a prerequisite for correctness and maintainability)? And if you can estimate that tradeoff, which is more important to the goals of your application?
As a side note, it is far more important to make sure you are using efficient algorithms and data structures than to make minor local optimizations. I've seen programmers use bizarre local optimization tricks in a module that ran in exponential time rather than log time.
Sheesh, evil *and* a jerk. -- Jade
Common idioms should be compiled away, like !x or x!=0. Uncommon idioms can't and probably shouldn't be attempted, i.e. if(!(x-x)) (which is always false). Ask your compiler maker and see if patches can be made for these types of things. 'cause if you think to do it one way, chances are, many others may try it too. It would be for their benefit to make a better compiler.
-
ping -f 255.255.255.255 # if only
What about code that is more complex? Now that compilers have matured over years and have had many improvements, I ask the Slashdot crowd, what they believe the compiler can be trusted to optimize and what must be hand optimized?
Programmers cost lots more per hour than computer time. Let the compiler optimize and let the programmers concentrated on developing solid maintainable code.
If you make code too clever in an effort to try to pre-optimize, you end up with code that other people have difficulty understanding. This is leads to lower quality code as it evolves if the people that follow you are not as savvy.
Not only that, but the vast majority of code written today is UI-centric or I/O bound. If you want real optimization, design a harddrive/controller combo that gets you 1 GBps off the physical platter (and at a price that consumers can afford).
The most important optimization is still the optimization of the algorithms you use. Unless under the most extreme circumstances, it doesn't really matter anymore whether the compiler might generate code that takes two cycles more than the optimal solution on today's CPUs; instead of attempting to work around the compiler's perceived (or maybe real) weaknesses, it's probably much better to review your code on a semantic level and see if you can speed things up by doing them differently.
The only exception I can think of is when you're doing standard stuff where the best (general) solution is well-known, like sorting; however, in those cases, you shouldn't reinvent the wheel, anyway, but instead use a (presumably already highly-optimized) library.
quidquid latine dictum sit altum videtur.
The only solution to this is to TEST.
Otherwise I go this way:
Is the compiler older, and not designed for current coding practices?
Think of it this way, if it were vb.net you can say isNULL(VAR) or (VAR = VBNull.Value)
The vbnull value was recently added, while isNULL has been there forever.
I use the VBNull.Value because the writer of the compiler was thinking about the new objects and wrote NEW code for it. isNull was probably a copy of an old coding practice.
Long story short: Use Newer objects if you can.
Why not create your own compiler?
I like suggestions, but I don't like contributing towards them.
I got in the habit of writing "readable but inefficient" code, taking care that my constructs don't get too sophisticated for the optimizer but then depending on gcc -O3 thoroughly. And then it happened I had to program 8051 clone. Then I learned there are no optimizing compilers for '51, that I'm really tight on CPU cycles, and that I simply don't know HOW to write really efficient C code.
Ended up writing my programs in assembler...
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
As a simple example, take 'if (!ptr)' instead of 'if (ptr==NULL)'.
Both forms resolve to the same opcode. Even under my 6502 compiler.
CMP register,val
JNE
Enjoy,
It's just the normal noises in here.
It's always a good idea to practice good coding. This way you'll not only depend on the compiler to do all the coding, but you'll also remain Sup3R l33t.
IGB: More fun than eating oatmeal!
1) Code for maintainability
2) Profile your code
3) Optimize the bottlenecks
That said, (!ptr) should be just as maintanable as (ptr == NULL) simply because it is a frequently used 'dialect'. As long as these 'shortcuts' are used throughout the entire codebase they should be familiar enough that they don't get in the way of maintainability.
An example would be searching and sorting algorythms (I know there have been thousands of variations, and entire libraries now exist, but theres always some other need for a non generic search function)
I could write sloppy code which appears to be significant, but then realise that holding this here, and keeping that register there, then I can do such a thing just a fraction quicker than before.
Its not so much going to the assembler level anymore, but a tightly coded loop tuned by human intuition will almost always still be faster than anything an optimiser can give.
I recently had an issue with sorting collections containing thousands of none trivial objects. Every time I adjusted the adready fast quicksort, I gained a little more speed.
Its always been the way, and until genetic compilation and optimisation comes along trying every combination, it will continue to be the case.
liqbase
What you're talking about it micro-optimization.
Compilers are pretty good at that, and you should let them do their job.
Programmers should optimize at a higher level: by their choice of algorithms, organizing the program so that memory access is cache-friendly, making sure various objects don't get destroyed and re-created unnecessarily, that sort of thing.
"ptr == 0" must give the same result as "ptr == NULL", always.
Isn't this a huge research topic in itself. And I am confident that we will get better compiler optimizations as we go forward. This makes us come to next question about code complexity. I always believe simpler code would also help compiler to help optimize code better apart from user readability. At this same time when we talk about compiler optimizations it is useful to understand the underlying hardware which has capacity to increase the Instruction level parellelism (ILP) and introduce its own optimization using pipelining.
Take the two sample ways to implement and then compile them. Then look at the MSIL that is created, if they are the same, then they were optimized to be identical. This works for most simple constructs, such as the one in the message body. If they are different then you have to know the relative costs of what the MSIL is doing in order to figure it out.
...are doomed to repeat the biggest trap in computer programming over and over again:
"Premature optimization is the root of all evil"
If there's only one rule in computer programming a person ever learns, "Hoare's dictum" is the one I would choose.
Almost all modern languages have extensive libraries available to handle common programming tasks and can handle the vast majority of optimizations you speak of automatically. This means that 99.99% of the time you shouldn't be thinking about optimizations at all. Unless you're John Carmack or you're writing a new compiler from scratch (and perhaps you are) or involved in a handful of other activities you're making a big big mistake if your spending any time worrying about these things. There are far more important things to worry about, such as writing code that can be understood by others, can easily be units tested, etc.
A few years ago I used to write C/C++/asm code extensively and used to be obsessed with performance and optimization. Then, one day, I had an epiphany and started writing code that is about 10 times slower than my old code (different in computer language and style) and infinitely easier to understand and expand. The only time I optimize now is at the very very end of development when I have solid profiler results from the final product that show noticable delays for the end user and this only happens rarely.
Of course, this is just my own personal experience and others may see things differently.
TIME(1) TIME(1)
NAME
time - time a simple command or give resource usage
SYNOPSIS
time [options] command [arguments...]
DESCRIPTION
The time command runs the specified program command with the given
arguments. When command finishes, time writes a message to standard
output giving timing statistics about this program run. These statis-
tics consist of (i) the elapsed real time between invocation and termi-
nation, (ii) the user CPU time (the sum of the tms_utime and tms_cutime
values in a struct tms as returned by times(2)), and (iii) the system
CPU time (the sum of the tms_stime and tms_cstime values in a struct
tms as returned by times(2)).
With regard to your example, I can't imagine any modern compiler wouldn't treat the two as equivalent.
However, in your example, I actually prefer "if (!ptr)" to "if (ptr == NULL)", for two reasons. First the latter is more error-prone, because you can accidentally end up with "if (ptr = NULL)". One common solution to avoid that problem is to write "if (NULL == ptr)", but that just doesn't read well to me. Another is to turn on warnings, and let your compiler point out code like that -- but that assumes a decent compiler.
The second, and more important, reason is that to anyone who's been writing C for a while, the compact representation is actually clearer because it's an instantly-recognizable idiom. To me, parsing the "ptr == NULL" format requires a few microseconds of thought to figure out what you're doing. "!ptr" requires none. There are a number of common idioms in C that are strange-looking at first, but soon become just another part of your programming vocabulary. IMO, if you're writing code in a given language, you should write it in the style that is most comfortable to other programmers in that language. I think proper use of idiomatic expressions *enhances* maintainability. Don't try to write Pascal in C, or Java in C++, or COBOL in, well, anything, but that's a separate issue :-)
Oh, and my answer to your more general question about whether or not you should try to write code that is easy for the compiler... no. Don't do that. Write code that is clear and readable to programmers and let the compiler do what it does. If profiling shows that a particular piece of code is too slow, then figure out how to optimize it, whether by tailoring the code, dropping down to assembler, or whatever. But not before.
Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
In my experience (if you're using a half-decent compiler), ANY "hand-coded" optimization will save you AT MOST a few instructions or clock cycles, and this is only in rare cases. Anyone who really needs the extra .000000001% difference is probably coding it in Assembly already.
BTW, 'if (!prt)' and 'if (ptr==NULL)' yield the exact same code but I prefer the former because I think it's clearer.
I don't worry about something, unless its NP complete, On^2, or running over and over. Its not about individual statements, unless they're nested deep in a loop... In which case its probably best to work in assembly. Its a high level programming language for a reason: You're not supposed to care for the running time.
If it does matter though, you want to analyze your code for where the slowdown occurs. Once you isolated the part, you can try several tecniques to speed up your code. Pick the one that runs the fastest.
God spoke to me.
That's why I code everything in pure assembly.
Look for my new OS coming to a computer near you in 2125!
When I started programming about, oh, 20 years ago this kind of stuff was really important to me. But these days my number one concern is *maintainability*.
I write my code in the simplest, shortest, most readable way possible, and then benchmark and optimize after I'm done. 90% of the time I don't even have to optimize.
I think if you take this attitude, your projects will turn out a lot better. Machines are pretty fast and CPU's do a lot of wacky stuff under the hood.
Now, if you actually do need the level of optimization you describe, you have only one choice: learn assembly and learn how your CPU works. You have to learn assembly and study the output of your compiler. For instance if you want to know the difference between !ptr and ptr==NULL, compile it both ways and check the output. And repeat whenever upgrading any part of your toolchain. Benchmark it too, because a bit of code that looks like it might be slower might actually run faster on today's CPUs!
Personally, I would use ptr == NULL because it's clearer what you mean. I only use "!" for boolean values. For example, when testing for the end of a string, I would use "*str == '\0'" instead of "!*str".
(Note, it's been a while since I've done hardcore C [Ruby is my language of choice these days], but I seem to recall that the C standard says that ptr==NULL is the same as ptr==0 [even if the implementation doesn't use 0 as NULL internally, for some reason], so your two code snippets should be identical I think.)
Then, if the program seems slow where it shouldn't, PROFILE. If profiling indicates that optimization should be applied, then and only then start arranging things first so that the algorithms and data structures provide nicer performance. If and only if that fails or is for some reason unapplicable, then you can start looking at things like low-level optimizations. (Pipelining, etc.)
Most of the time crap like if(!ptr) is actually worse than if(ptr == NULL), since in the first case the pointer is first converted into a boolean value (or, in C89, an int) and then checked against false. If you are working with a compiler that was built after 1990, you'll do well to trust the compiler's own optimization routines over this sort of anal-retentive smartypants micro-optimization.
(Not to mention that if(!p) is downright evil if the pointer nature of "p" can't be determined from immediate context. And anyhow, avoiding implicit conversions is usually the way to go in any language.)
If you're really, truly, deeply concerned about how well a particular piece of code is optimized, the only way to be really, truly, deeply sure is to Do It Yourself for the particular processor you are using.
;-)
Unless it really needs to be optimized, and I speak as a person who reads others' code a LOT, PLEASE go for readability over obfuscility.
Mark
"Programs should be written for people to read, and only incidentally for machines to execute."
- Structure and Interpretation of Computer Programs
Just write the bit of code you're curious about in both ways you'd like to compare, then look at the generated assembler. You don't even need to know much about assembler.
No need to Ask Slashdot about it.
I don't believe the compiler can be trusted with more complicated pieces of C++ code, as they can be too hard for a compiler to know for sure that the optimization won't be destructive. The biggest example is when using the STL (or just about any class with iterators like that). Take the follow code:
//stuff
for( iterator itr = items.begin(); itr != items.end(); itr++ )
{
}
Will the compiler recognize that the return value of the postfix ++ operator isn't being used, and can therefor use the faster prefix operator? Probably not, because it won't know for sure that the two methods really do accomplish the same thing. While in general this is the case, its possible that someone's code may not operate that way, causing wierd bugs.
Stuff like this pops up more and more when you make code like this that makes heavy use of classes and templates. Because of that, I don't trust the compiler to figure out it can use "++itr" instead, so I tell it to do that myself. That is just the first one I can think of, but there are many more.
With that said, you in general want to choose the one that is the easiest to read, even if it is slower. Code maintainability is generally more important than speed IMO.
Each compiler is different. Some will optimise things other won't.
In general, however, systems are now fast enought that when in doubt, write the clearest code possible. I mean for most apps, speed is not critical, however for all apps stability and lack of bugs is important and obscure code leads to problems.
Also, for things that are time critical, it's generall just one or two little parts that make all the difference. You only need to worry about optimizing those inner loops where all the time is spent. Use a profiler, since programmers generally suck at identifying what needs optimising.
Keep it easy to read and maintain, unless speed is critical in a certian part. Then you can go nuts on hand optimization, but document it well.
Sutter and Alexandrescu had some advice about it C++ Coding Standards (I would think it would apply to other languages too).
Don't optimize prematurely and don't pessimize prematurely.
Micro optimization is useless unless you know for sure that that particular code segment is a bottleneck. OTOH, there are no reason you should pass stuff by value if you can get away with passing it by reference, or do i++ instead of ++i.
As someone pointed out earlier in the disccusion, choosing the right algorithm is more important.
Je ne parle pas francais.
Already have the fastest box? Wait six months.
Hand optimize code in places that are called a lot, and places that take a lot of processing power. Use the compiler for tasks that are not intensive. However, if you call one task a lot either as a subrotine or in a loop, hand code that to be as optimized as you can. Likewise, routines that are heavily processor intensive should be hand optimized to improve performance. Optimizing anything else won't provide as much of an over all boost in performance.
Fly me to the moon Let me sing among those stars Let me see what spring is like On jupiter and mars
LLVM is an aggressive compiler that is able to do many cool things. Best yet, it has a demo page here: http://llvm.org/demo, where you can try two different things and see how they compile.
:)
One of the nice things about this is that the code is printed in a simple abstract assembly language that is easy to read and understand.
The compiler itself is very cool too btw, check it out.
-Chris
Processor Tech & JIT compilers are killing hand optimized code. Not only that, but hand optimized code is often detrimental on AMD while beneficial on Intel or vice versa.
if(story->isOnFrontPage())
{
postDupe(story);
}
else
if(story->sumitter == "Roland")
{
post(story);
}
Donald Knuth was quoating Tony Hoare when he said that.
*sigh* back to work...
Far too many programs reads data from files periodically. Harddrive cycles are extremely expensive, and in my experience, one of the most common reasons for slow programs.
if you are going to maintain that code, just be sure you know what it does 2 weeks after you write it
<sarcasm>'cause you just now wrote it, and i don't know what it does</sarcasm>
vodka, straight up, thank you!
Do you really need your code to run as quickly as possible? If so, by all means, use whatever coding tricks you want. Just be sure to add comments to deobfuscate.
OTOH, if fast enough is fast enough, then code clarity will pay off far more in the long run.
Please donate your spare CPU cycles to help fight cancer and other diseases
...but I'd say test your compilers. Find the right fit. If the compiler doesn't optimize or doesn't optimize the way you'd want or expect then change it. I've tried gnu c++ compiler. I like it. But I don't care about optimization. So I didn't pick it based on that. I chose it based on free beer. A buddy of mine said it wouldn't work as well as Borland's. Depending on the task it's better. So he owed me a case.
Regardless, since coders are a choosey lot, you're best bet in my mind is to play around until you find the one you like.
I have to say I like the analogy between Embedded versus Desktop. One would think embedded compilers use better optimization but I would also think, based on some code I've seen, that embedded coders also hand optimize as well. Is there such a thing as double optimization?
Rivendahl
... there is nothing that has not already been thought
These days, unless you're doing something really weird, it's not about machine performance but about programmer performance. For the average application, who cares if some calculation takes 0.005 or 0.006 seconds?
What however does matter, is the fact that your code is clean, understandable and easily maintained and extended by other programmers.
Someone else said this...
"Code is not about telling a computer what to do, it is about telling other people what you are telling the computer to do."
So, what is more intuitive?
if(!myPtr) or if(myPtr == NULL or if myPtr is null
C's terseness has only ever served to exclude other people and make them feel inferior.
Generally the compiler will do a good job optimizing on code written for human understanding. Remember computers are still getting faster, and that will more than compensate for most of these small tricks you are thinking of. Like that post earlier, a good choice in algorthim is more important that these little guys. So code it up and then see how it performs. If it gets the job done right (always the most important thing), and in a reasonable amount of time, you are finished.
If perfomance turns out to be a problem, the other trick is to find the place in your program where it spends most of the time (if there is one). Optimize that or part of it will usually generate the needed improvement.
1MIPS microcontroller.
1000 samples per second required.
Need to gather 4 ADC input values, 4 binary port input values, perform some calculations, perform sanity checks, handle errors and send the digest and status over RS232, plus intercept interrupts in the meantime.
1000 cycles becomes horribly tight limit. And the compiler doesn't optimize.
If you write code and it needs optimizing, you will hand profile and optimize. If it does not need optimizing, you won't.
Simple.
Good judgement comes from experience, and experience comes from bad judgement.
- W. Wriston, former Citibank CEO
Maintainability is much more important than optimization. If you do find a slow section of code, it can almost always be optimized in a way that leaves it maintainable. Real hand-optimization involves using a better algorithm, reducing the number of function calls, reducing branchs, and at worst, adding more variables to avoid performing the same calculations repeatedly within a loop. None of these require you to compete in an obfuscated C contest!
Trying to optimize in your head rarely does any good... Use a good profiling tool (like Apple's Shark) to find out what part of your code uses the most time and then just concentrate on making that part faster.
Using a profiler and your own brain you can often significantly improve over what a compiler can do.
There are 10 types of people in this world, those who can count in binary and those who can't.
Those that advocate the constant first in if boolean comparisons are the feeble minded who believe ever bit of propaganda and PC reporting they read.
It's especially annoying to see it done in programming languages like Java where assignments are not even allowed in if statements. When I see java code like this:
if (0 == x)
I'm thinking "loser".
Back to C. And besides gcc since C-99 has issued warnings for assignments in the "if" expression when not embedded in parenthesis.
example...
if (x = 3)
if ((x = 3))
Look at "freeware" programs. Some are made by only one person and as "freeware" usually implies only the binary being distributed, there are cases where only that person (and perhaps the occasional close friend) might see it. Also, some of us (myself) like to compile programs by ourselves just to see what we can do, or even to ready up for the next programming course. I'm can't possibly be the only person who does this. (...right?)
You can hold down the "B" button for continuous firing.
Keep in mind that the guys who wrote the compiler's optimization code are experts at this sort of thing. In most cases, they know quite a bit more than you do about it; as long as your code is clear enough for the compiler to figure out, it'll probably do better than you could. I recall reading an example somewhere years ago, maybe in Code Complete, about two source listings. There was the original vanilla version and the hand tweaked code. Although the tweaked code was more 'optimal', and ran faster without compiler optimizations, the vanilla code ran much faster when optimizations were turned on. This is because the original code was clear enough for the compiler's optimizaiton code to understand and do something much more clever with.
* Obviously, there may be some domains, such as embedded, wherein this may not apply. The embedded experts can comment here :)
Only sissies use compilers. Real men code in binary.
An Indian-American Hindu committed to non-violent thought/speech/action alarmed by the global explosion of radical Islam
Like others have said, legibility of code comes first. Those tricks may have been useful in the early 80s, today they will save a negligible amount of processing time.
Instead, you should first focus on writing correct code and optimize later. If anything, you should optimize I/O access and memory management. The if (!ptr) trick may save a clock cycle here and there, while your program writing to disk when it doesn't have to could cost you six orders of magnitude more.
Still, there is no formula. The most sensible approach is to write correct code with a modular design. Later, when the need arises, you can optimize the relevant modules only.
Unless someone is writing code for an embedded device that usually has strict memory and/or timing requirements, why write shortcut code at all?
I think writing clear, understandable, human-readable code should be a priority over writing code that might be optimized to the hilt by the compiler but very difficult to read and comprehend. This is something that my programming instructors and most textbooks have emphasized over the last few years.
All you need to do is look at the code that is produced by the compiler to know if optimizations of these sorts are important. I think you will find that the commercial compilers will make efficient code in almost all cases, especially on simple cases like the ones listed in the article.
Once upon a time I was a crack assembly programmer optimizing clock cycles and memory hits, but at some point in the 90's, the compilers started to write better code than I could without significant effort. Compilers now know all about cache efficiency and pipelining and never forget to use that special code sequence to save a memory cycle.
The upshot is, you should trust the compiler and code for clarity.
Personally, in your example, I prefer the former incarnation. The == makes me look twice to figure out to what you are comparing.
Anyway, the only thing I really worry about any more is data locality. Say you have a 2D matrix foo[x][y]. Matrices get linearized in memory. If you loop rapidly "across" the grain performance will be poor and it's difficult for compilers to optimize this away (assuming you aren't writing trivial code with array sizes that are known at compile time). If you are really stretched for bandwidth between the processor and the RAM and you have a higher dimensionality then pointer+offset will be faster than using [][[][][][] access.
Hehe, having seen some truely awful code where I work (in Java too!) I've always been amazed that our apps run quickly let alone at all. I think unless you are writing some intensive processing loop go for the neat code.
From another point of view though I've always found clever optimisations very interesting (eg. pixel plotting).
A quick note on the desktop vs. embedded compiler issue, since nobody seems to have touched on that: in my experience it makes virtually no difference. An embedded application is more likely to use some judicious hand-tuned assembly when needed for speed, but compiler optimizations are generally comparable between the two platform categories -- not surprising, since many if not most embedded compilers are derivatives of GCC and have the same optimization core anyway.
This line of thinking is (sadly perhaps) dated. I am thinking back in the day when code had to be painstakingly optimized to be stored and executed with minimal hardware resources. Like those video games squeezed into 4 KB of ROM. Nowadays most of the languages folks use are high level programming types. Newer programmers hardly worry about malloc types of things and the nittty gritty. This might not be the best way things are evolving, but with the hardware power and resources that are out there it's true.
Ask a profiler. Write the clear code, and profile it. If there's a performance problem, then optimize. If you don't think your optimizations will show up when profiling your app, then your optimizations are worthless.
Don't even bother with this kind of stuff, for simple things like this the compiler will generate adequate code for you if you do one thing or another. If you focus exclusively on the small things, you tend to lose focus on the bigger picture. Case in point, recently a co-worker was so obsessed with optimizing the logic in an "if" statement to be faster once compiled that he ended up writing logically incorrect code.
:)
If you want to write fast software you are much better to think about the overall design and choose a design/datastructures/algorithms that are efficient. You can hand-optimize the crap out of a O(N) search, but my compiler-optimized O(log N) search is going to kick your butt.
Also, everyone knows that its if (NULL == ptr)
I've worked with code that needed to be high-performance. For instance: converting texture data in memory, which is a loop executed (texture size) ^ 2 times, and so it gets used a lot. I've tried a lot of things on these loops to speed them up, but things like (!ptr) vs. (ptr == NULL) are so slight I can't even measure their effect on a loop called a million times. So, over the course of a million trips through the loop, the net savings (if there was any) was less than a millisecond. Shaving less than a millisecond off of something that takes ~400ms is an almost worthless "optimization".
I've experimented with other things as well, such as using an unsigned char instead of int if I know the value won't exceed 255, and for me the difference is always too small to matter (or even measure) on today's processors.
Of course, every application is different, and I'm sure in many cases it DOES matter, but I would make sure this is something really, REALLY CPU intensive before I started worrying about (!ptr) vs (ptr == NULL). Code readability is important, and you don't want to make sacrifices just so the menu pops up 1ms faster for the user.
--This sig is in beta. Please let us know abut any errors you find.
Short variable names indeed. Some book authors make me laugh.
A few books of programming that I've used, they all use the infamous i counter name in their for loops and then, they come up and say that you have to give variable names that make sense, and then you see again the for int i...
Instruction-by-instruction optimization by hand is only productive for guys like John Carmack, where each nanosecond really does count. If you're really worried about this, why not just write it in assembly?
Hamster
IMO, It's better to start out in your development with the most readable code. Once you have created something larger, you have to go back and analyze what portions of your code can benefit from a optimized re-factor as opposed to which portions of code a refactor would only squeeze in a few ticks. In addition, as compilers get better, your optimizations may only slow down your program in newer compilers, or introduce unusual bugs.
I think that the more important question is "Should I bother to hand optimize my code at all?" since as you pointed out we don't really know how the compiler is going to optimize everything. It could take your perfectly optimized code and ruin it completely, thus wasting all of the time you spent optimizing.
Personally, I try to write code that is easily readable by myself and others. If it isn't readable by someone in the future, it does no good IMHO. I say write the code how it is easy to read, and let the speed of modern processors, and the advancement of compilers do the hard work.
Now, of course I don't mean you should write terribly slow algorigthms just to be neat and tidy, you should still take the time to think of a good/clean/fast snippet of code as well.
I think it's a bid ridiculous that you're contemplating trying to optimize the case for "ptr == NULL" versus "!ptr".
Even *if* (and this is a *big* if) the compiler produces slightly different code based on the two, I very, very highly doubt that there will be a significant noticeable performance difference.
It's far better, IMO, to make the code legible. And, I think that it will be far more to productive to optimize asymptotic complexity (e.g., trying to write an O(n) replacement for your O(n log n) algorithm) than trying to fiddle with such minor things like this.
What the hell do you need a compiler for.
Just program you code directly in machine language and it will be as efficient as you can write it.
Or if you must use a compiler use FORTRAN or some other old language that has had the compiler crunched for effecieny.
My Sig indicates the end of the comment I posted.
"This mission is too important to allow you to jeopardize it." -- HAL
Seriously, why would you waste your time obfuscating your code when you don't have too? Unless you know through profiling that detailed statement level code is bad then you are shooting yourself in the foot.
This isn't to say that when making architecture level decisions that you shouldn't optimize. O(N^2) is bad, Um'Kay? O(N) is alright for small N, but O(log N) is better when you know you'll have a significant N. That's the stuff a compiler can't do for you today.
Once you've profiled, and you know something is critical and can be done better and matters, then start obfuscating. There is a lot you can do in C to optimize, especially with DSP codes, so resorting to ASM should only be done for the most extreme cases.
"This mission is too important to allow you to jeopardize it." -- HAL
The answer in the past was debateable, but usually ended up concluding that you are better off focusing on writing clear code, and letting the compiler handle the optimizations.
Nowadays, compilers are extremely sophisticated, and can perform very convoluted (and yet, ultimately efficient) optimizations that even the most seasoned programmer wouldn't devise. I've tried this myself with several different compilers, where I code the same algorithm the "clear" way, then re-do it, trying my damndest to make it tight, compact, and efficient. When I compared the output bytecodes/assembly, they were identical. In the former case, the compiler made all kinds of optimizations anyway. In the latter, the compiler had still come up with some optimizations that I hadn't thought of, and in some cases, ignored my own optimizations in favour of an even more efficient way.
Trust your compiler. A helluvalot of thought has gone into them, and they can optimize far better than you can ever dream to.
Like woodworking? Build your own picture frames.
Think of it this way: Someone had to program and compile the compiler itself, so if he puts no shortcut-enabling features into it to help with performance and whatnot, then he's going to get junk. What do you think he'd want from his own program, junk or perfection?
Take a look at the ASM listings. If you're using VC++ then you will have to set the compiler to generate ASM listings in the project settings.
You don't have to know hardcore ASM to be able to compare how good of job the compiler does with examples such as the one you provided (!ptr vs ptr==NULL).
Dan East
Better known as 318230.
I've always been told that it is best to write vanilla code and to trust the compiler to optimize for you. The compiler is much happier with plain ol' code. It says, "Hey! I know what to do with this!" Rather than some elaborate crap you've written because you think it'll be faster. That's when it says, "Ack! WTF am I supposed to do with this? Oh well, here goes nothing..."
I once made an experiment with some long forgotten version of gcc. I tried two pieces of code against each other:
(while *to++ = *from++);
vs.
while (1) {
to[i] = from[i];
if (0 == from[i]) {
break;
}
i = i + 1;
}
For some strange reason the second version came out ahead by a very slight margin. The generated code looked more or less identical to me at the time, so I expect it was a caching issue. Nevertheless, unless you have proven that > 90% of execution time is spent in a very localized part of your program, don't bother optimizing.
//Wegge
mov ax,ptr
or ax,ax
jz _skip_if
but if (ptr == NULL) will generate:
mov ax,ptr
cmp ax,0
jz _skip_if
For most compilers it's about the same. With compilers for 386/486/Pentium there can actually be a speed advantage when using !ptr along with other logical operators because the compiler will use assembly language instructions like SETZ which sets AL to either 0 or 1 depending on the Z flag in one instruction instead of 3.
I think previous posts have a point about how NULL isn't necessarily (void*)0, but I have yet to see such a compiler (Can anyone name one?) so I'm generally in the habit of using !ptr.
I have however used an old DOS compiler where !ptr doesn't detect NULL pointers properly when used with far pointers and I must explicitly compare against NULL (Mix C compiler v2.x if I remember correctly).
A good programmer once told me that the 3 steps to writing programs are:
Most people never get past step 1. Unless runtime issues are severely limiting your ability to debug, optimizing is the step you take when you have nothing left to do. :-)
Just look at IE, still modifying its old code (from the versions so far) to stay compatible with old Web pages and programs that use its WebBrowser control. It's gotten far more secure but still has a long way to go; it'll need teh ol' teardown & rebuild to compete with Firefox and malicious users.
You can hold down the "B" button for continuous firing.
Back when I was doing real-time programming in FORTRAN-II on a PDP-11/34, I was able to very slightly decrease execution time by changing "divide by two" instructions to arithmatic shifts and "square root" operations to "power of 1/2" (because x^.5 = sqrt(x)).
Since those instructions were in a loop that was running 80,000 times per second, this meant that I could get more data when destructively testing rocket motors... in the end, I got a 40% increase in processing speed that was worth a whole lot of money to the company. AND it got me a raise
The answer to your question is TEST your unique combination of hardware and software, find out what works better/faster/more-elegantly, and use the most human-readable form that you can afford to given your unique requirements.
If you are doing real-time digital data acquisition involving usecond events, you will probably end up with some pretty cryptic source code, so be nice and put in lots of comments.
If you are programming an office automation application, your code should probably be readable by kindergarteners, since you won't have very difficult performance requirements.
..in optimising something like a manual data input routine to save a couple of nano-seconds. If there's a core function repeated several million times and _must_ run quickly then write the damn thing in assembler in the first place.
:)
No, write for clarity assuming an idiot is going to maintain your code - that idiot could likely be you...or me
Once I was a four stone apology. Now I am two separate gorillas.
to suggest this.
You LOSE.
and you don't know how to read come asslember and check for yourself?
The reason someone might use the former code snippet is because they believe it would result in smaller machine code if the compiler does not do optimizations or is not smart enough to optimize the particular code snippet.
;-)
On modern CPU architectures there won't be a speed difference even if the compiler is brain-dead. Personally I use if (!ptr) because I think that is the more clear form
For the example that you gave, you should write (variable == NULL) because it is easier for anyone reading your code to understand. It is also kind of logically strange to say (!variable) if variable is not a boolean value, because that logic operation implies that it is.
For other examples like that, the same goes. In this day and age, minute optimizations are not worth putting in if it will degrade the clarity of the code, which is far more important. In any case, modern compilers will make such optimizations for you.
You may not know if ptr is a smart pointer in c++. An operator!= would then have to be written for every type the smart pointer class would interact with.
Therefore you should do.
(ptr != 0)
Best advice is to code in a readable and consistent format. Profile your application after you're done and work on any real sore spots then. Let your experience give you some ideas on optimizations when you architect the system where it matters.
80-90% of your code won't need optimization in the real world, profile it and find that 10-20% that does. That will make a big difference.
Open Source Java DAO Generator
...is the root of all evil. Stop wasting your time wondering about whether or not you should "hand optimize" and run the damn profiler.
Worrying about 'if (!ptr)' vs 'if (ptr==NULL)' is not how you optimize code.
There are three steps to optimizing code:
1. Instrument your code to find out in what routines it is spending most of its time.
2. Optimize the places where it spends the time. Choose a better algorithm, do the work in the background if it suspends user interaction, precompute and do table lookup, substitue an approximation if that would suffice. There are many many tricks. Trying to second-guess the compiler is not one of them.
3. Goto 1.
Ceci n'est pas une signature.
Now if you still think that if (!ptr) is evil than the bad guys have won
If it needs optimization so much that you can't trust the compiler to handle it, you should be coding it in assembly.
I am trolling
Premature optimization is the root of some evil.
Frankly, I'd code it as:
if (NULL == ptr) {
}
And then use the profiler later to see what needs to be optimized.
Avoid Missing Ball for High Score
Seperate things out into functions and get it to work first. When your program works then worry about optimizing it, one subroutine at a time.
A winnar is me!
Free Mac Mini Yeah, it's
Don't forget that compilers are designed to optimize normal code constructs. If you come in with something truly bizzare the compiler might just make things worse because it doesn't know what to do.
Trust a compiler? A heartless assemblage of algorithms and logic? Are you insane??
Using ==NULL instead of ! doesn't make anything clearer, unless you don't know C well enough to know what ! does. In my opinion, bulking up code with unnecessarily longer idioms and whitespace actually makes code harder to read.
If you don't know what that means, you're wasting everyone's time.
Mike Hoye
In the first case, I could see a dumb compiler actually using the NOT operation and then testing for zero, whereas in the second case you're just testing for zero explicitly.
Then again, I could see a dumber compiler testing against zero twice in the second case.
But these aren't really concerns with the good compilers available to us today, so just use which is clearer.
Honestly, I wish C had perl's 'unless' operator for these cases, because the ! is just aesthetically unpleasing.
Buckle your ROFL belt, we're in for some LOLs.
Sorry, this may be horrible OT...
Several years ago, I was in the position to hire a software developer. I asked for code samples, and this kid gives me a print out. I swear to $DEITY there wasn't a single carriage return in the C code he showed me. When I asked about this, his reply was "I like to write tight code."
Then they will know what the compiler can and can't optimize and will know what to put their effort into.
One time I was talking to a guy who was writing a program in assembly and asked why he wasn't using a higher level language. He told me it wouldn't be fast enough. So I asked him if he does strength reduction and loop invariant removal by himself. His reply: "Huh?" If he doesn't appear to understand such simple common compiler optimizations, I'm almost positive the compiler would have done a better job than him. I didn't tell him that, though.
...just my 2 gil.
I went through a phase where I tried to get every last little bit of speed out of everything. Problem is, that often leads to harder-to-maintain, or less correct, code.
I don't believe in the camp that says "screw optimization, just buy a faster CPU". However, I also don't think it's worth sacrificing readability or portability to chop out a few cycles here and there.
Use your optimization brainpower on choosing and implementing faster algorithms; that has the potential of making vast differences in the speed of your apps. As for individual lines of code, do what is most readable and correct and portable.
BTW, I prefer "if (NULL == ptr)" - put the constant first. Slightly less readable, but will not compile if you accidentally type "if (NULL = ptr)". Once you get used to this it's not a problem to read, but it saves me a bug a few times a year.
int a[10];
7[a] = 1;
I had to deal with a large project that was written entirely with this assembly-like syntax.
Understanding some programmers' code is hard enough. Optimize for readability.
> I have been coding in C for a while (10 yrs or so) and tend to use short code snippets.
> As a simple example, take 'if (!ptr)' instead of 'if (ptr==NULL)'.
> The reason someone might use the former code snippet is because they believe it would result
> in smaller machine code if the compiler does not do optimizations or is not smart enough
> to optimize the particular code snippet.
No programmer believes that.
In C, NULL is #define-ed to 0 and the "!" operator also compares against zero so every compiler should generate exactly the same code for both.
> IMHO the latter code snippet is clearer than the former, and I would use it in my code
Actually I prefer to write (and read) the former and I do find it clearer, mostly because it is idiomatic in C et al.
Another good reason is that the former works better in C++ because it enables you to substitute "smart" objects for plain pointers and use them in a more natureal way (especially in templates).
(Aside: most platforms that have C compilers also have deccent C++ compilers)
> if I know for sure that the compiler will optimize it and produce machine code equivalent to the former code snippet.
See above. There is nothing to optimize.
Actually, I am using the second form a lot in C++. Consider this:
Error error=dosomething();
if(error==0)
handle_error();
and this:
if(Error error=dosomething())
handle_error();
The second form gives the variable error a shorter scope, thus preventing misuse (as in: 'oh! I need a temporary variable. Let's recycle error, as it is not used anymore.' Yes, that does happen quite often, unfortunately)
Along the same lines:
if(Resource resource=getresource()){
use_resource(resource);
}
Write your code so that it's readable (to you, now and always) and understandable (to others if it's not just yours). Really, you're not going to gain anything trying to beat the compiler these days. After your project is done, then profile: chances are your bottlenecks will be much larger in scope than whether (!ptr) of faster than (ptr == NULL).
Given that most of code's life is in the maintanance portion of the life cylce. I beleive that clearer code will perform better in the long run regardless of the optimizer. The reason that I hold this belief is that future programmers will be more likely to make efficient modifications to code that they can easily understand. A lot of programmers fear modifying code that they don't thoroughly understand and will often make mods in a manner that avoids changing the "scary" code. This often results in redundant code and redundant database calls being written. (boy i guess i work in a real hack shop!). Finally if you look at efficiency in terms of dollars the clear code is a hands down winner. Modifying the clear code will be able to be done quicker and result in less bugs.
The only code segments you really have to worry about hand optimising are loops which happen a huge number of times.
In scientific computing, a loop which does most of the calculation and runs hundreds of thousands or maybe millions of times is the most critical to get right. After all, one millisecond lost per loop may mean a day's extra computation time.
A great deal of the optimisation has to be within the algorithm, making sure that you don't do unnecessary computation. However, some of it is to do with knowing how CPUs work. If you order the calculations in the correct way you can aid the compiler in its optimisation buy helping to work on data which is likely to be kept within the registers rather than flitting about and having to swap the values out to cache, or even worse, main memory.
Agrajag: "Oh no, not again!"
As your specific example of 'if (!ptr)' vs'if (ptr==NULL)', regardless of whether or not one is more optimized than the other, there is really is little difference between the two in terms of readability, since everybody who would need to read the code would understand that. But !ptr may be a better choice for another reason: typos. A coder would be muchs less likely to mistype !ptr than he (my apologies for that last pronoun to the female Slashdot readers out there, all three of them. But I digress) than he would ptr==NULL, since more keystrokes = more opportunities to make little mistakes. As proof of that, I recently had to type in a missing NULL into the code of Nautilus' print manager because it wouldn't compile without it.
Grrr, you named the algorithm that must not be named! Cursed be the name of the fool who thought it would be a good algorithm for introductory students - I've lost count of the number of people convinced that this satan-spawned algorithm is faster than an insertion sort (it's not) and that there's no reason for them to learn to use the qsort() function. N.B., not to implement a quick sort, but to simply call a standard library routine.
The most frustrating thing is that, if you must use the algorithm that must not be named, the bidirectional form of the algorithm is much faster (in practice) than the unidirectional form yet really no more complex to code than the latter if you have any potential as a software developer.
For every complex problem there is an answer that is clear, simple, and wrong. -- H L Mencken
"I have been coding in C for a while (10 yrs or so) and tend to use short code snippets. As a simple example, take 'if (!ptr)' instead of 'if (ptr==NULL)'. The reason someone might use the former code snippet is because they believe it would result in smaller machine code if the compiler does not do optimizations or is not smart enough to optimize the particular code snippet.
...
If I were paying programmers to write code for me, and one such programmer lost sleep over such trivialities, it would be time to start looking for another programmer.
As a programmer, unless specifically dictated otherwise by special requirements or by job title (i.e. your job title is "Pendantic Optimizer of Trivial Instructions"), your job is:
a) Reduce complexity.
b) Reduce complexity.
Software is complex. You have enough to worry about without trying to determine how a compiler will optimize down to the level of a single instruction. If you're optimizing for one compiler, you're killing performance for another -there's very little to lose and so much to gain from not trying to optimize at the instruction level during the construction process.
Yes, there is the odd exception to this rule (perhaps speed/size constraints for embedded software, off the top of my head), but man - I couldn't imagine trying to code something worthwhile and worrying about things like this with each and every key press
I recently attended a code optimization workshop for the IBM PPC compiler for Mac OSX. The compiler designer stressed that hand optimized code (i.e. unrolled loops, register variables, stupid pointer tricks etc.) only confused the optimizing compiler and would usually result in slower code overall when -O4 and higher optimizations are enabled. He provided a number of examples why this was the case and convinced us that modern compilers are much better at optimizing than humans. He also stressed the need to profile code and look for things the compiler cannot optimize. Examples are using double floats where single precision will suffice and in the case of the PPC unecessary conversions between floats and integers.
They only thing I avoid is pow for finding a simple square of a number, better just to use x*x. Other than that write the code so you can read it 6 months from now and know what you meant.
Onward to the Aether Sphere!
It is if you recognize the reference.
Some of the source can be seen here.
Even at the algorithm level, don't optimize before you know that you have a performance/resource problem. But you better write code so clean that changing to a new algorithm isn't major surgery.
I took a sophomore level intro to systems programming course and for one lab we had to optimize various segments of code. Problem was, the compiler knew most of the tricks the lab was trying to teach us. The compiler was already unrolling loops and using intermediate variables to avoid calculating the same value over and over again.
The only place the compiler wasn't ideal is in optimizing code for a certain associatvity and size of cache. In other words, it's not especially worthwhile to heavily optimize code unless you know the computer architecture you're writing for very well. If you're writing multi-platform code, just forget it. Spend the time considering your choice of algorithm.
Ialwaysstripallthewhitespaceoutofmyprograms.
It has been my experience that it is better to write clear code, which also means clearly understandable algorithms. The vast majority of the time the compiler will optimize better than a person can anyway. If during testing it is determined that the program runs to slow, then start worrying about optimization.
10: PRINT "Everything old is new again."
20: GOTO 10
you do work in a hack shop! but i agree.
I took a compliers class a year or so ago. We had to make a complier in c using lex/yacc for pascal. We also put in some optimization in it. But or profressor who has been doing this for around 10 years or so alwasy said to never trust a complier for optimizing your code. most don't do a very good job of it. and each complier optimizes stuff diffrently. some even broke code. His comparisons were using gcc, ibm complier, and a couple others, as well as optimizing in the code itself. The optimized code ran better in 90% of the runs.
Much though I admire Knuth for TAOCP and \TeX,
I have to disagree on this one. Code duplication
(i.e., failing to refactor and/or not abstracting
sufficiently) and data duplication are far, far
worse than any optimization. The only drawback
of optimization is that it wastes time, or at
the most clarity. I guess he himself never
experienced any inability to abstract, which would
explain his blindness to duplication as the
greatest of 'harmfulnesses'
> Every programmer worth his/her salt knows that
> source code is self documenting...
And it's true too. Although comments are indeed a good thing, writing code that does not require them is a much better one. If your code needs comments, it's probably too complex for continued maintenance.
Doing the same thing for (!ptr) and (ptr == NULL) isn't an optimization; in either case, the compiler will almost certainly use a "branch if not zero" instruction. If it doesn't, it's an even chance which of the versions generates worse code.
..."
The only consideration is which is the clearer code, and the answer to that one is whichever is used most in the surrounding code, or, if you're just starting, whichever the programmers are most accustomed to. In this case, "(!ptr)" is more clear than "(ptr == NULL)", because it's what you've been using.
Personally, I greatly prefer "!ptr", because I generally think about the code in terms of whether the pointer is valid. I tend to write "if (ptr) use(ptr);", and I find "if (ptr != NULL) use(ptr);" confusing, like saying, "if pointer isn't no good,
I suggest you strive for clarity in your code and leave optimization later when you're done coding. This is to ensure you don't optimize prematurely and besides it usually takes a longer time to write optimized, compact code.
The second thing is you should always try not to optimize - in other words optimize only if the performance of the program is not satisfactory. And even this should be done by locating the bottlenecks and rewrite lines to reduce overheads and cycles. You should keep in mind that you should not optimize the whole entire program.
As for performance issues, most of the time it fallbacks to the design of the program you're coding for - the algorithm. Obviously it will do little use to optimize an unefficient algorithm, trying to squeeze every bit of speed and is no doubt slower compared to using the right one.
Bullshit. Some basic checks on performance are always appropriate as part of your debugging. For example, on MacOS X, I recommend you at least do two things in your app:
1. Run top and look at the amount of CPU usage your app has during different parts of its operation. It should not, for example, run at 99% CPU usage while idle.
2. Run QuartzDebug to make sure you aren't doing gratuituous amounts of extra drawing. Examples: redrawing more often than necessary, redrawing more area than necessary.
And yes, for the average application, I still care about these things.
If certain operations seem to be slow, run an optimization tool and see what "low hanging fruit" you can address.
I've worked on several professional applications and while some of them are "weird", some level of optimization has always been important.
Avoid Missing Ball for High Score
The biggest problem with helping the compiler IMHO is common subexpression elimination, and code hoisting. Making sure that invariant code is only executed once is sometimes harder than it sounds, owing to the fact that, for obvious reasons, compilers must have a very conservative idea of what "invariant" means.
Function calls are a good example, especially if the call is to a function in a different .o file. If I call sin(5) once and cache the return value, instead of every time I go through a loop, will it change the behaviour of the program? Of course the answer is "no", but telling a compiler about that can be tricky. gcc uses something like "__attribute__ ((const))" to flag a function as having no side effects (off the top of my head), but no one ever uses it (if for no other reason than it only works with gcc). If a compiler doesn't know that a function has no side effects, it's not going to optimize around it very well :(
My advice for programmers worried about speed is to be const-correct wherever possible, and to bring computations outside of loops whenever possible. Other than that, I can't think of anything that a compiler can't do infinity times better than all the world's humans put together.
I've gone to a few seminars on compilers and compiler optimizations and it's really amazing how well compilers do in regard to optimizations. You'll often also find that the place where you think there are bottle-necks are really not most critical part of the code. This point was discussed in "Refactoring: Improving the Design of Existing Code" by Martin Fowler. His advice is to write code for yourself and for other coders and such. Only after you have something that works and has nice clean code should you think about optimizations. Refactoring will often make it easier to optimize later if you need it.
I also think it may be possible to defeat your compilers optimization techniques by trying to optimize yourself. I'm not a compiler person and only have had one experience to lead me to think this. But for an algorithms class we were discussing the advantages of using sentinel values when sorting data, something about being able to eliminate the check for whether the current index is past the end of the array for each iteration. Anyway we actually had to write two different implementations of this sorting algorithm in C and mine was actually slower in the sentinel value version. The only explanation I could think of was that there were some optimizations going on which relied on the loop being of a form, and changing it around caused it to loose this optimization.
We always knew Comcast was corrupt, here's the proof: http://tech.slashdot.org/comments.pl?sid=1909890&cid=34545432
Everyone is just saying, "don't optimize a line of code, optimize your damn algorithm," which is dead on.
However, the guy is still asking a *somewhat* valid question. His mistake is in optimizing prematurely. After his code is correct, if there are reasons that it would be better if it were faster, he should optimize his algorithms. After he optimizes his algorithms, if there are still reasons that the code needs to run faster, then he should try single line optimizations like the one he describes on the bottleneck inner loops. Check the results with a stopwatch. You don't have to know the first thing about the state of the art in compiler optimizations.
Maybe he's found a situation where less readable, hinky code is worthwhile. You only find that out after you've discovered a performance problem.
The remaining interesting question is, what is the state of the art in compiler optimizations. I haven't a fucking clue. And I don't know whether it's better or worse in embedded systems. I code database GUIs in VB for a living. You can optimize my code when you pry it from the runtime's cold, dead hands.
I played around with sun's cc optimizations in my compiler course in college, and it did a pretty good job of sniping the low-hanging fruit, like unused branches & loops & etc. Since I was not (am not?) much of a programmer, I couldn't imagine what the challenging aspects of optimization would be, so I couldn't poke around.
I guess the general rule is that you should use the chip vendor's compiler, right? Intel's compiler has always been faster than gcc and VS C/C++ in the past, and IBM's stuff certainly beat the pants off gcc for POWER/PPC. And Sun's cc was oodles better than gcc in my little toy tests in college four years ago.
There are no trails. There are no trees out here.
if (0!=ptr) is a hideous abortion, because it's not readable
My, my, but aren't you the wordsmith...
You maybe meant aberration or abhorable? Abortion means the premature end of something, in today's society most likely the premature end of a pregnancy. In any case, if (0 != ptr) is perfectly readable for anyone who's written more than a simple "Hello World" routine.
ANSI C: "The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant."
The definition of a null pointer constant: "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant."
Source: Programming languages - C (ISO/IEC 9899:1999)Make your code clear, never mind a cycle here or there during compile time or run time. Chances are that the optimizer will squeeze quite a bit out of it, but even if it does not, except in some rare and/or degenerate cases, the computer your code will be running on will probably be so extremely overpowered for the task that you won't notice the difference.
However, in comparison, the amount of time saved by the code being clear to the next programmer to view it will be invaluable.
Also, please consider your algorithm carefully. Make sure that it isn't spinning its wheels a lot, else your (!ptr) vs (ptr==NULL) really isn't going to make a lot of difference.
Of course, it goes without saying that you can ignore my comments if you are entering the Obfuscated C Contest. :-)
www.wavefront-av.com
Almost any other platform has exactly the same ability. GCC lets you inspect the assembly, and gdb (as I recall) allows you to view the disassembly for any given line while debugging.
I am TheRaven on Soylent News
With all the bloated code out there, I'm suprised that anybody is even concerned about optimization. The original poster must be the only programmer left that even bothers to think about optimization...
If it doesn't work fast enough it's often cheaper to buy faster hardware.
Perl Programmer for hire
Boeing qa testing requires that each and every machine instruction be executed at least once for the embedded systems in their aircraft.
So if (a != 0) || (b != 0) does not get short circuited in testing.
Now, when it comes to optimising your bottlenecks at the end, take into account that compilers really sucks at optimising. Badly. Last week, I was debugging this line of code:
a /= 4;
I had to come to the horrible conclusion that the compiler had taken this integer division and made it into a library call to the divide function. Solution:
a >>= 2;
I write my code legibly. I test and debug until it is correct. Then I look at the generated assembler (objdump -DS is your friend). Then I rewrite my C code until the compiler generates somewhat decent machine code.
I have always liked while(!done)... that reads to me... "while not done" and seems really clear to me that somewhere in that clause will be ways of setting done=true.
... is that really any more clear?
I've had that corrected by respected colleagues to "while (done == false)"
I remember when the if (!ptr) thing looks confusing, so I understand, but I had been programming only a couple months at the time, quite long ago, and is it bad for that to make sense? Don't get me wrong, obviously this is different from my while example because strictly speaking, NULL does not have to equate to "false"... it just happens to on about every architecture made. The "while" version is more defensible, because !done really is the same as (done == false), even if false is not (int)0.
-pyrrho
Even a simple sequential read loop that exceeds the L1 cache can benefit greatly from the appropriate cache hints in the assembly (prefetchnta and its variants).
Toss in a second processor and a NUMA architecture, and everything gets even more fun.
For examples of the hacks you can do on Opterons that vastly improve simple C code speed, take a look at the stream.c source and see AMD's technical pubs no. 25112, 24592, and 32035.
--Pat / zippy@cs.brandeis.edu
The reason someone might use the former code snippet is because they believe it would result in smaller machine code
Anybody who uses "if(!ptr)" because he thinks it generates better code these days should be banned from programming in C (but then, we probably should just ban C programming altogether).
IMHO the latter code snippet is clearer than the former
I think there is a good chance that you don't actually understand what "if(ptr==NULL)" means. For example, if "ptr" is of type "int", can you answer the question of whether the compiler will give you a type error?
Ultimately, no amount of macro magic (like NULL) is going to fix C's pointer system, so one might as well go with the most portable expressions. It's an unfortunately fact that NULL has often been defined inconsistently (in fact, there are half a dozen different definitions scattered through dozens of Linux header files), so I avoid it in my code. Any C programmer worth his salt should have no problem with "if(!ptr)" or "ptr = 0", and those will work consistently on just about any C compiler in existence, no matter how old. It's unfortunate that it looks obscure to the uninitiated, but, hey, that's C for you, and in this case, I think the cure is worse than the disease.
...then the code isn't important enough to optimize. Plain and simple.
Never try to optimize anything unless you have measured the speed of the code before optimizing and have measured it again after optimizing.
Optimized code is almost always harder to understand, contains more possible code paths, and more likely to contain bugs than the most straightforward code. It's only worth it if it's really faster...
And you simply cannot tell whether it's faster unless you actually time it. It's absolutely mindboggling how often a change you are certain will speed up the code has no effect, or a truly negligible effect, or slows it down.
This has always been true. In these days of heavily optimized compilers and complex CPUs that are doing branch prediction and God knows what all, it is truer than ever. You cannot tell whether code is fast just by glancing at it. Well, maybe there are processor gurus who can accurately visualize the exact flow of all the bits through the pipeline, but I'm certainly not one of them.
A corollary is that since the optimized code is almost always trickier, harder to understand, and often contains more logic paths than the most straightforward code, you shouldn't optimize unless you are committed to spending the time to write a careful unit-test fixture that exercises everything tricky you've done, and write good comments in the code.
"How to Do Nothing," kids activities, back in print!
Oops - forget about that last point. I was thinking about an unrelated algorithm. This is why I always code from CLR, complete with assertions and page references in the comments. It doesn't matter if the algorithm is fast if it's also wrong.
For every complex problem there is an answer that is clear, simple, and wrong. -- H L Mencken
I have to confess that I'm guilty of this too, but you'll gain much greater speedup out of your code when you understand your data structures.
Classic example-- in the middle of a loop, calling size() on std::list<T>. (for the ignorant, that's typically O(n), although I suspect the ISO standard simply doesn't guarantee that it's constant time). I'll abuse it simply because I'm lazy, but it makes me cringe every time I see it in otherwise well-written code.
So long, and thanks for all the Phish
When I read
if (!ptr)
in my head I think "if not pointer" which I interpret as not pointing to anything. When I read
if (ptr==NULL)
in my head I think "if pointer equals null" which I interpret the same way. As a result, I end up writing the former because it consumes less ocular and mental bandwidth.
The compiler will perform strength reduction in all reasonable instances.
The compiler will raise invariant computations from inner loops in almost all cases that do not involve pointers.
The compiler knows how to optimize integer division in ways I wouldn't have even thought of.
The compiler sometimes "forgets" about a register and produces sub-optimal code for inner loops.
The compiler can't always tell what variable is most important to keep in a register in an inner loop.
Other stuff:
x^=y; y^=x; x^=y; optimizes to an XCHG instruction with gcc on x86. I was amazed that it could do that. (Yes, that piece of code exchanges x and y). On the other hand, tmp=x; x=y; y=tmp; doesn't get optimized to an XCHG. Obviously, the compiler is using a Boolean simplifier or identity-prover.
The compiler always assumes a branch will be taken (unless you use certain compiler switches to change this behavior). Thus you should always arrange your conditional tests so that the less-often executed code is within the braces.
Don't be afraid to write complex expressions. Subexpression elimination is almost foolproof in all instances where pointers are NOT involved. It's better to leave your code clear, and let the compiler optimize it.
And ABOVE ALL:
No matter how much the compiler optimizes your code, you can throw it all down the toilet with bad design by screwing the cache utilization. This is EXTREMELY important especially in graphical applications which process huge raster buffers. Row-wise processing is always more efficient than column-wise. Random access will kill your performance. Do not trust the memory allocator to keep your allocations together. Write your own allocator if you are dealing with thousands or millions of small, related chunks of information.
I could go on... But I must also second what others have said, which is to perform algorithmic optimizations FIRST and do not bother with constant-factor optimizations until you are CERTAIN that you are using the best algorithm. If you ignore this advice you might waste a week optimizing a three-line inner loop and then come up with a better algorithm the next week which makes all your hard work redundant.
First off, !ptr is easy to read for any C coder. In addition, in an embedded system, speed and/or size may matter more.
But with that said, I agree with you on general systems. In this day and age, even for MOST embedded systems, memory and cpu power is cheap enough, that code maintence becomes a costly issue.
I prefer the "u" in honour as it seems to be missing these days.
We've got a guy here who seems to think it necessary to write conditionals like this:
Drives me nuts. What the hell is wrong with just
??John.
Probably 95% of your code doesn't even need optimization. I program for embedded devices with real-time functionality, but even so I've rarely had to optimize anything other than Interrupt Service Routines and similar Critical Section code. Most normal code in a modern application will have plenty of time to run no matter how sloppy it is. It takes a lot of inefficiency before things bog down.
>>As a simple example, take 'if (!ptr)' instead of 'if (ptr==NULL)'.
>>...
>>IMHO the latter code snippet is clearer than the former, and I would use it
Please, PLEASE tell me you wouldn't use "ptr==NULL". For Pete's sake, tell me you would use "NULL==ptr" instead. Forget optimizations - the first "intermediate" thing you learn in C++ is to ALWAYS put the constant first in equality comparisons so that in case you accidentally use only one "=" some day when you haven't had enough caffeine, the compiler will catch it for you.
It doesn't matter how fast your code runs if it isn't correct. One should almost always prefer a correctness tradeoff over a performance tradeoff.
I find most of these comments about writing "slower" clean code, to be suspicious at best, in my experience (10 years of c++, Bsc CPSC, MSC CPSC in progress, contracting, coop ... you get the idea) cleaner well written code dosn't perform significantly worse than highly hand tuned code. Humans just arn't good at deciding when certain optimizations should be employed, like unrolling loops, inlining, placing certain vars in registers ...
The comments about premature optimizaion, and profiling are bang on.
The only time I resort to hand optimizations now is in embedded microcontroller applications where there are significant hard limits, like memory, and stack and code space. Some of the microcontrollers I use only have 256 bytes of ram, 4 levels of stack, a couple of k of program memory, and run at about 1mhz, so optimizations are justified but other than that don't waist everybodies time.
deAngelo
If programming in C, as your examples have shown, use the "register" keyword in parts you're not sure will be optimized by the compiler all too well. Examples of this are blocks that use numerous variables, some of which are referenced more than others, blocks that make many function calls, so the compiler knows not to send everything to memory before loading the new frame in and in situations where it would appear a variable won't be used for awhile but you know the function coming next is going to want to manipulate it. Luckily, most compilers have good enough optimization that using "register" ins't as valuable as it once was. Just make sure that when you use it, don't set all variable to "register" because that defeats the purpose. Just the ones you know will be referenced a lot.
Another obvious clue is use effeciant data structures and algorithms. Plan your code before you write it and try and prove your algorithm is running in the fastest possible time.
Also, to get an idea of what most modern compilers do to optimize, and thus allowing you to see if what you hav written is not going to get optimized, read the Dragon Book, or at least the last few parts where this is discussed. What is said there still to this day are some of the most common techniques to optimize code. If you give this some time you will be able to analize what part of your code won't get optimized well.
As for your example, both conditional statements you provided would most likely get the same asm code generated. Probably along the lines of a beqz (branch if equal to zero) statement or an equivalent. Your statements are both boolean and comparing a variable to a constant, 0. Semantic analizers would pick up on this immediatly.
Also, in C don't ever pass by value but that should be obvious to anyone getting paid to code in C.
Lastly, if a part of your code doesn't seem optimal, it's probably a function of your poor algorithm and not that of the compilers code generation. I would doubt you will write a better asm program than your compiler would. Write a new algorithm and use tools to inspect your bottlenecks, like many others have pointed out.
"If you are a dreamer, a wisher, a liar, A hope-er, a pray-er, a magic bean buyer
As an embedded device driver developer, I tend to err on the side of the compiler NOT being smart. In most cases, the compiler is smart enough to do the right thing. Many times, it optimizes different ways of writing the code into the same machine code, however, there have been instances when the compiler I've been *forced* to use didn't do this. For this reason I always leave the decision to myself and not the compiler. This also means knowing enough about how the particular compiler does things to make the informed decision. For desktop / user-level developers, however, this probably isn't necessary.
"The best laid plans of mice and men gang oft agley..." - ROBERT BURNS
comments can be misleading, but the code never lies, it always works exactly as written.
-pyrrho
"...programs must be written for people to read, and only incidentally for machines to execute."
Clarity first. And assume the compiler knows what it's doing.
Google "literate programming" for more supporting material.
Actually I think that some small local optimizations that are done by programmers prevent the compiler from being able to do deeper and more fundemental optimizations.
The point being that the programmer should write clear understandable, readable, maintainable code and let the compiler do the optimizations. Its its job. If your compiler is not doing a good job then get another compiler.
A good example in point is the Fortran compilers these days because of their more restrictive structure and good optimizations benchmark at 20 times faster than the equivalent C or C++ code of the same algorthims. And not hand optimizations will catch that up. Check it out, for heavy numerical and array processing use Fortran. Not because of the language but because with the language and a good optimizing compiler, magic happens.
"Ask slashdot elementary facts about programing in C."
As several readers have already pointed out, not only does the author not grasp the basics of C but he doesn't really understand what good optimization is all about. Why does this qualify as "news for nerds"? There are plenty of good sites that discuss this topic in general. Here are a couple from the FIRST PAGE of a google search
Optimizing for embedded systems
From the dsp perspective
paper from a professional on the subject
That last paper begins with this sage advice
All of that found in ONE google search on the FIRST page and I'm QUITE SURE it took far less time than submitting a "story" to slashdot.
Here's a hint editors. Take a lameass story like this and turn it into something worth discussing.
Instead of letting someone ask "what's the difference between these two things that are clearly the same to any experienced programmer", how about rephrasing that to one or more of the following questions which are more general and might trigger LESS inane banter.
What kinds of low level optimizations do C compilers do for you automatically and what kinds of things are they unable to determine?
Under what conditions is it worthwhile to hand optimize C code and are there situations where writing assembler is necessary or recommended?
What specific profiling techniqes do you use to determine where your code is spending its time and what kind of gains can you expect to receive by tweaking the existing code vs rewriting it in a different algorithm?
In what ways do you apply the 90/10 rule when developing and optimizing code?
ymmv.
Normal Programmers:
Don't do it
Expert Programmers:
Don't Do It
Unless it's requested but the user.
Nobody will most likely read it but I type this anyway.
About 100% of real and bad performance problems I've seen this far has been design problems and the algorithm selection problems. And most often the former one is the real problem. We can make plenty of code, but our design usually isn't made for performance. One single bad way to handle SQL queries can sink the whole software to the deep dungeons of bad performance. One single SQL scheme design desicion can throw us to middle of the deep sea of bad performance.
And to the orginal q... at C++ if (!ptr) is suggested. It's more portable than if(ptr != NULL)
When I wrote my ray-tracer for the final project of my graphics class, I used gcc -o3 and it optimized my code into Pov-ray, which was sweet. I was done with the project in like ten minutes.
Plus I got extra credit for implementing phong shading. I didn't even try to do phong shading.
Every C-programmer (who earns the title) knows that if(!ptr) and if(ptr == NULL) give the same code. But many find the former just as readable if not more. Just look at the kernel sources.
I highly doubt the submitter really does C for 10 years.
As a DSP firmware developer the only code I can rely on is the code I generate myself. For most signal processing applications, speed is the most important objective and sacrificing readability (which can be remedied with good comments) is well worth a few extra cycles. You really can't trust a high level language compiler to always pick the best method for a particular task.
From the sound of your post, I'm assuming you already understand the bit about premature optimization and are now at the point where you must do it anyway. Slashdot is probably not the best forum for this, as they all have great hardware and compilers and wouldn't understand how someone could actually care about saving 1/2 microsecond of execution time on a 60MHz machine.
My last round of optimization was in a complex control loop running in a 20KHz interrupt on a 60 MHz part. This code was eating about half the available processor time, and reducing it by a few microseconds freed enough time to add 15 percent to the background code - which is quite substantial. It was a series of 13 different improvements slightly more complex than the example you gave. I don't recommend doing this stuff all over the place, but when you need to the only way to be sure is to do real timing tests - sometimes things you think will help don't and things you think are the same are better... And it mostly depends on the compiler you've got.
!foo means just: foo == 0, and the compiler has to check the value anyway, since most CPU architectures can only branch on a flag in the condition register.
;)
Don't worry, just use whatever is clear. I prefer "if (!foo) error", but that is a matter of taste. Just be consistent.
That quote applies to what language you chose to write in as well. Tight VNC's Java client is actually faster than the (windows) native client... it's nearly twice as fast at playing movies at least. Smalltalk's GUIs are indistinguishable from native GUI's even though they are painting their own components because their painting code is elegant and sweet -- that's despite the best smalltalk being 4x slower than Java, which is around 1.5x C. Of course, you don't want to do math in Python, but even though Python is on the order of ~100x slower than C at math it's still useful for a LOT of programs.
These languages let you easily use the right algorithm. There have been countless times in C where is was just too much damned trouble to use the right algorithm (would take 20 lines of customized code instead of one-line method call) or do the proper checks. As far as I am concerned the ONLY reason to program in C is if you MUST HAVE excellent performance. Otherwise it's just a waste.
That is quite an awe-inspiring read. Thank you.
Here's what I have to say on the topic:
1. Do not optimize _code_, optimize _algorithms_ , architectures and SQL schemas, and do so only in the case when you're 100% clear that there will be a sizable benefit.
2. If you do #1, don't do any optimizations until you've done at least preliminary perf testing and identified the bottlenecks. It's important for perf test to mimic real workload as close as possibly. Half-assed test scenarios are about as good as no testing, and sometimes worse because they give you the false sense of confidence, when in fact you should have none.
3. If you're making changes in an existing product, measure improvements under _varied_ workloads. Collect and study the trend data.
4. Don't optimize stuff which does not get called/accessed often or where you know the benefits of optimization will be minuscule. I've seen some programmers optimize error logging to avoid a fucking _function call_ (for some reason they thought it was expensive) and then turn around and do horrible performance decisions in SQL schema.
5. Don't optimize without first talking to your perf/stress person (if you have one). If you don't have a perf/stress guy, hire one. Some developers think they know a lot about perf and optimization, while in fact all they know are urban legends. So they spend a bunch of time on urban legends, and the real perf issues remain in the product. Your perf guy, if he's good, KNOWS what's broken and how to fix it. Listen to what he has to say a little more.
6. Pay the most attention to shared resources and threading issues around that. In this day and age, processors are blazingly fast, so the most common source of perf problems is locking on a shared resource. Do code reviews on code that's heavily multithreaded and employs a lot of locking. If you use MS SQL server, run Index Optimizer and see what it has to say. Also, run Microsoft PSS "Blocker" script under a real world workload to see if you're having locking issues.
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
Have fun: Join D.N.A. (National Dyslexics Association)
be sure that level of optimization is really needed.
I can't tell you how many times I found a developer 'optimizing' code to save a millisecond..for a desktop application.
If you are pulling data drom a database, optimizing the call in a manner that save 1 second isn't worth the effort.
Of course, the story mentions C, so I assume this person is writting low level code.
The Kruger Dunning explains most post on
If you're writing performance critical code, or just using a new compiler or target, it can be educational to look at the output of "cc -S". Does the assembly code match what you intended to do? Is the optimizer doing stupid things, possibly because of language rules and the way you wrote the code? Sometimes you can learn things about the target architecture by seeing examples of architecture dependent "tricks" in the generated code. The programmer who wrote the code generator probably knows a lot more than you about what is optimal for the target.
Mea navis aericumbens anguillis abundat
I ask the Slashdot crowd, what they believe the compiler can be trusted to optimize and what must be hand optimized?"
This question needs be considered, because the poster is staring right at the answer and is still missing it. You can write code. You have a compiler. OPTOMIZE THE COMPILER. That's the beauty of open source. Pry open the insides of GCC and tweak it so that it optimizes your code better. If you're a decent programmer, submit the idea back to the community. For some reaon people don't seem to remember that your compiler is just software too, it's not sacred, optimize to your hearts content. I don't know if this is because people are too used to closed source compilers or very high level programminging languages like Python and Ruby.
If you look at the Nullstone website, they have an excellent list of optimizations to expect from a compiler and a few to hope for. It must be remembered, however, that some of these can produce wrong answers such as illegal hoisting if the compiler isn't tested thoroughly enough. You must remember that you can make code very, very fast if you don't care about correct answers and useful results. Remember your priorities!
-Those who would give up essential liberty to purchase temporary safety deserve neither. -Ben Franklin
When you develop your code, go through the first time and write it from the perspective of simplifying maintenance and development. If you need to speed up performance of some aspect of the code, you can go through and do optimizations later.
This sig has been temporarily disconnected or is no longer in service
$ cat one.c .file "one.c" .file "two.c" .file "one.c" .file "two.c"
#include
int main( int argc, char* argv[] ) {
if( argv == NULL ) return 0; else return 1;
}
$ cat two.c
#include
int main( int argc, char* argv[] ) {
if( !argv ) return 0; else return 1;
}
$ gcc -S one.c
$ gcc -S two.c
$ diff one.s two.s
-
---
+
$ gcc -O3 -S one.c
$ gcc -O3 -S two.c
$ diff one.s two.s
-
---
+
$ gcc --version
gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)
No diference at all...
Knuth was hardly blind to the harmfulness of duplication. He used to require his students to hand-write coding assignments so that the pain of duplicating code would be appreciated, and abstraction would be rewarded concretely, or so the urban legend has it.
Your post could be optimized for clarity by not hitting return every six words, BTW.
Socialism: a lie told by totalitarians and believed by fools.
You are seriously worried about a C compiler optimizing a NULL compare? How mind-numbingly unproductive. You should see some of my code. I program in a real high-level language (SML). I use a real high-level compiler (MLton). I count on the compiler to do things like flatten my data structures, turn unknown function calls into switches and do closure conversion of my inner functions. The computer industry needs to stop living in the 1950s. If we had 1/10 the man hours put into compilers for high-level langauges like SML/Haskell/OCaml as has been put into C compilers, we would be able to produce 2x as fast code without _ever_ worrying about abstracting.
What does .NET have to do with this? This is exactly the same for practically any compilers, and most modern compilers can generate textual assembly output so you can trivially look at the differences.
And believe me it is a pain in the a$$. Our company did the verification for the code in the microprocessor that controls the locks to the bathroom door on a 777, if the crapper tank is full then the door locks to make sure there isn't an overflow and thus frozen turd/urine meteors that fall from the sky. Every byte of the code MUST be excercised including all error conditions.
The valuable things are a programmer's time, and time between release cycles.
Custom, hands-free Linux installs. Instalinux
and tell them the way they speak would be better if people from other countries could understand it?
Just curios cause clearly you don't understand C++, yet you are being critical to the posters perfectly legable code.
The Kruger Dunning explains most post on
First off, X and x are different variables.
Second, x >> 24 fills with the sign bit if x is a signed value, and with 0 if unsigned.
Third, you probably want | instead of &.
If you check your C defines, NULL is actually a C value defined in stdio's tree of includes, not in mem or sys. NULL is meant for I/O use, not for use in comparing memory pointers.
Check the types. Most include files define NULL as something like: (0)
This is of type int, which you generally shouldn't compare to a type of void*. Your compiler will tend to catch it. While we usually expect that 0 is an invalid pointer, strictly speaking that's not guaranteed to be true on every system out there.
In C++, 0 is actually a valid and guaranteed empty memory address, but NULL doesn't exist, it's defined by a C header.
So no matter what C-type you're using, ptr == NULL is bad. Don't do it.
Slashdot. It's Not For Common Sense
I ask the Slashdot crowd, what they believe the compiler can be trusted to optimize and what must be hand optimized.
What can compilers trust the Slashdot crowd to optimize?
over either of those. You're less likely to screw up and assign NULL to your pointer (single equals requires modifiable Lvalue, so the compiler catches NULL = ptr). Any tricks you come up with to try to out-optimize the compiler are likely to make things worse in some future version of the compiler or on some other architecture you didn't think of. I don't mean write sloppy inefficient code -- if you initialize a value to the result of a function call and the result of the function isn't dependent on what iteration of the loop you're on, then of course, move the assignment outside the loop. Chances are that the optimizer might miss it if the function isn't inlined. But worrying about 1 machine instruction that might be saved if the compiler misses the fact that a test against zero doesn't require a subtraction is more than just a little overboard. Face it -- the compiler knows. The 5 times in your life when it makes a significant difference to get to that level of hand optimization will make themselves very clear to you. Until then, leave it up to the compiler.
First, reading through the existing comments, the general opinion appears to be, write clear code, unless you *really* need to optimize it. Ounce for ounce I have to agree with this.
Second, regarding the embedded system portion of the question, we have to remember that the rules for embedded systems are different than the rules for general purpose systems. Specifically, embedded systems are resource constrained and (more times than not) have real-time deadlines.
At least so far, I have never programmed an embedded system that I needed to optomize my code for speed (best case execution time), or for space. I have needed to change an algorithm around for complexity reasons, but never for minor incremental speed improvements.
Real time systems are more about executing on time, rather than executing fast. And yes, there is a difference. Pay close attention to your worst case execution time. If your missing deadlines occasionally, it is most likely due to unpredictable interrupts and other events in your system, not because the compiler couldn't optimize your code.
In short, regarding any compiler/code optimization you may want to do on your embedded system, write your code first to be dependable, predictable, and on time. Worry about raw speed later.
I remember in one of my first code reviews a peer dressed me down for writing "inefficient" code, specifically, I think it was my "while" constructs. I was dumbfounded! I was given the lecture on compiler optimizations, blah, blah, blah. I dug in and claimed bullhockey -- it was more important to understand the code, not even necessarily for other coders, but for one's self should one have to revisit code after a long absence.
I know compiler theory, and that's basically what it is... if you write code to home in on compiler efficiency, you're doing it on theory, you don't necessarily know your compiler will do what you think it will. And for those of you who "do", you don't know where else your code will go and be compiled. You run the risk of propogating obtuse code (submit to Obfuscated Code...).
Besides, there's nothing like aging code to improve efficiency... for some reason my code is written so well, it runs twice as fast about every 18 months.
And, per another poster, code not worth timing is not worth optimizing... I've never known a bit-head who "optimizes" C-code to time it to verify its improved efficiency.
If you're trying to speed your program up by writing source code to compile optimally, one of two things is happening: 1) you're at the bleeding edge, writing some inner loop that's gonna run 1E14 times on a Cray, or 2) you're wasting your time. I've always found that when my program is too slow, it's because I'm not using clever enough high-level algorithms.
Get garbage_in Make garabage_out Oh, I couldn't resist. I work in Config Mgmt after all... Seriously, forget all the optimizations in the world. No matter how good a compiler gets it can't fix code. Bad logic will still cause programs that run slow. Hard coding will still cause failures on some systems. Taking static source and turning into a runtime executable is no small task. To expect a compiler to make what you code better is a much greater task. Alas, we'll have to continue to write good code just a little bit longer. :D
Oops, how did this get here?
09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0
I've worked with a variety of processors and microcontrollers, and a number of development enviroments tailored to them. The results really varied depending on the priorities of the coompiler designers.
When dealing with PICs, I never bothered with using C, and instead just went straight to assembly. The PIC-C (how many pixies use PIC-C?)compiler did a really poor job, and I could write much more efficient code myself.
However, when I was designing audio filters on a TI test bed, there was no way I was going to write assembly for processors working in parallel and try to get it more efficient than what the compiler was going to offer. Besides which, that compiler offered various optimization priorities, like minimizing storage, memory use, or maximizing speed.
Of course, this is only 2 examples, but basically the only right answer, besides doing a little investigation to see what the compiler is actually spitting out.
The nose doesn't cause the tail.
Most insightful comment on this page.
So how many dumps does it take to fill up the crapper tank? I'd hate to be the last QA engineer in line to use the crapper. Also what happens when that last engineer fills up the crapper, does the bathroom door look thus trapping him inside?
With regard to (!ptr) vs (ptr == NULL), I will state the latter may look clearer, but is more prone to the = vs == error that has bitten too many programmers over the decades this language has been in existence.
I personally prefer the !ptr because my history includes over 13 years working inside the Un*x kernel at a half dozen computer manufacturers. During that time the == (double equals) typo has burned me more times than I care to remember.
When it comes to optimization, I go back to my days with MIPS where the optimizer will rearrange code to fill empty branch delay slots of that architecture with useful instructions from earlier in the code path that don't have dependencies. Debugging at that level was always an adventure, with or without compiler optimizations.
Premature Optimization is the DEVIL! I repeat, it is the gosh darn DEVIL! Don't do it. Write clear code so that I don't have to spend days trying to figure out what you are trying to do.
The biggest mistake I see in my professional (and unprofessional) life is programmers who try to optimize their code is all sorts of "733+" ways, trying to "trick" the compiler into removing 1 or 2 lines of assembly, yet completely disregard that they are using a map instead of a hash_map, or doing a linear search when they could do a binary search, or doing the same lookup multiple times, when they could do it just once. It's just silly, and goes to show that lots of programmers don't know how to optimize effectively.
Compilers are good. They optimize code well. Don't try to help them out unless you know your code has a definite bottleneck in a tight loop that needs hand tuning. Focus on using correct algorithms and designing your code from a high level to process data efficiently. Write your code in a clear and easy to read manner, so that you or some other programmer can easily figure out what's going on a few months down the line when you need to add fixes or new functionality. These are the ways to build efficient and maintainable systems, not by writing stuff that you could enter in an obfuscated code contest.
+1 Insightful, -1 Troll. What can I say, I'm an Insightful Troll.
Just remember that old 80 - 20 rule. 80% of the work is done in 20% of the code. 80% of the code is simple to write 20% requires some thought. And when humans do the optimizing 80 percent of the time the 20% of the code they optimize isn't the critical code to optimize. People make really poor choices most of the time for hand optimizations. And compilers are much better at consistently optimizing code these days. If you must, work on optimizing the algorithms used and let the compiler optimize the code. Clear concise code is more valuable and processors will get faster. If you must optimize the code, and we all feel that pull to do so from time to time, make sure you use appropriate tools to profile the execution of the code with realistic inputs/loads to choose where to spend your time optimizing. And check your before and after with the same load and profiling tools to make sure you spent your time well.
- Tjp
I am in wallow with my inner money grubbing capitalistic pig. ... Oink!
Most compiled programs don't need any optimization from the compiler or programmer because their performance is just not that important.
If the program must be fast your first concern should be getting the right answer. I can make any program lightning fast as long as it doesn't have to return the right answer. This may seem trivially obvious but you'd be surprised by how many times optimization attempts end up optimizing away the right answer.
Pick the right algorithm and implement it clearly.
If it's too slow, break out the profiler and optimize.
If it's still too slow, you screwed yourself by not including performance requirements at the very beginning. Maximum performance must be designed in from the start (e.g., look at high performance matrix multiply libraries)
Moderation in everything, including moderation.
Damn, it can get to that wrong answer fast.
The Kruger Dunning explains most post on
I use an assembler, you insensitive clod!
I use if(!ptr) rather than if(ptr==NULL) because it's less typing. Also if(!ptr) is conceptually clearer. read: "if not pointer". A 0 pointer is not a valid pointer, it's pretty simple. Verbosity does not equal readability. But like I said, mainly I do it because it's less typing. ! is way less of a reach on my keyboard than = too.
If you're actually worried about optimization, vague stylistic variations without any metrics attached is a waste of time. Profiling, Profiling, Profiling is the only way to optimize. You need metrics so you can use your time wisely and more importantly, so you can correctly evaluate risk versus gains. (ex: some complex bit of uber optimization only gives a 15% performance boost, it's close to the dead line and it's side-effects are not well known, perhaps you should put it off for the next release)
“Common sense is not so common.” — Voltaire
- How often are functions called (and branches taken)
- Which functions take most of the time
- See the assembler code for each line with a mouse click (no need to guess anymore)
callgrind/kcachegrind is by far the easiest profiling solution I ever tried, and it seems answer more or less all of your questions.150 Opening BINARY mode data connection for slashdot.sig (129323052 bytes).
I think that most people forget that the reason that i, j, k, etc. are used for loop counters is that unless otherwise declared, I..N default to INTEGER in FORTRAN. This convention just carried over as programmers migrated from FORTRAN to other languages and has been passed down through the ages.
(S(SKK)(SKK))(S(SKK)(SKK))
The programmer comes up with the fastest algorithm, the compiler comes up with the fastest machine code.
Duh?
How are you supposed to get called back to the gig if someone else can maintain your code, sheesh.
The Kruger Dunning explains most post on
First, the examples you give are identical in semantics: "if (!ptr)" and "if (ptr != NULL)" are exactly the same, regardless of optimizations. It's like saying "0.0" is faster than "0.00". There's no difference. Both "if" statements check a pointer against zero. There still has to be that test, no matter what.
:)
(As an aside, on some old CPUs like the 6502, flags were set when a value was loaded from memory, but this isn't the case on the x86 or PowerPC.)
So let's get rid of that example and go with something more traditional, like "a = a + 1" vs. "a += 1" vs. "a++". Now if you were writing a really, really naive compiler as a student project, or maybe one that was trying to generate code in one pass without generating any kind of parse tree, then there could be a difference between the resultant code. But in almost all compilers, a program is represented in a general, internal form. "a++" will likely be turned into the equivalent of "a = a + 1" in this tree, to reduce special cases. Then the tree goes through all kinds of optimization passes, possibly even being turned into different intermediate languages in the process, all before code generation takes place. And it's all so trivial to generate "inc eax" instead of "add eax,1". This is all business as usual for at least the last 35 years. It was done before that, too, but I don't know if I'd call it business as usual then
This is a good one we used in undergrad and grad CS programs (nice reference):
9 6/ ref=pd_sxp_elt_l1/002-5294359-9337643
http://www.amazon.com/exec/obidos/ASIN/02010002
The Design and Analysis of Computer Algorithms (Addison-Wesley Series in Computer Science and Information Processing)
by Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman
thank you, thank you very much.
The Kruger Dunning explains most post on
Being that the bathroom isn't flight critical that code was probably only done to DO-178B Level E or maybe D. The software for flight critical components like displays and flight controls is scrutinized much more heavily.
I would use if (!ptr) for a different reason. It is not hard to accidently type if(ptr = NULL) instead of if(ptr == NULL) thereby accidently add a reason for your program to segfault.
If you are going to do this, it is better to do if(NULL == ptr) so that if you omit one of the equal signs, it won't compile.
In the end we can argue these things forever. People see code differently and may find one idea elegant and easy while the other unmaintainable and unreadible. Sort of like the thread v process debate (ongoing for now what... 30 years?).
LedgerSMB: Open source Accounting/ERP
If (ptr==NULL) is poor style because it could lead to a = being deleted and overlooked, much safer to write if (NULL==ptr). if (!ptr) is equivalent in standard C++, however, both will compile to the same object even without optimization on most compilers.
would you also type "if( bDoIt == true )" instead of just "if( bDoIt )" ? i'm not saying one way or another is better, but i don't think anybody would use the former in your example just because they are concerned about compiler optimization (or the lack thereof) i would use it because it's less to type and arguably just as clear and meaningful to anyone who's familiar with the language.
if(!ptr) should be read as "if not ptr".
// an infinite loop // booleanizes a value // an if..else friendly way // clear some bits
The less-verbose code is easier to read.
It's a standard idiom too, which means you
damn well better do it that way so that
others can more quickly read your code!
It's not something you need to think about,
just like these:
for(;;);
a = !!b;
#define c(d) do{foo(d); bar(d);}while(0)
e &= ~0x04008201;
If you had to think about any of those, you're not
a serious C programmer. (Sorry! Read all the kernel
patches to get used to the C language.)
Compiler optimisers
I've used quite a few compilers - both desktop and embedded - in anger. Most of the desktop compilers are really quite good at micro-optimisation. The embedded compilers are more of a mixed bunch.
More specifically
GCC (for x86 and PowerPC) is a very good compiler these days. Some of the other ports (notably ARM) are pretty poor at optimising for instruction set features (some optimisations come for free on all ports as they are done before code generation)
Microsoft, much maligned though they are, produce good compilers, although I have found that their 'maximum' optimisation level can sometimes be a little too aggressive, and produce unexpected results in some cases (I found this with eVC++ for ARM, for example).
You may guess what I do for a living if I say that the ARM toolset produces superb code, with optimisations which can account for specific characteristics of Cache, MMU and pipeline. It is difficult to better this compiler in assembler unless you really know what you're doing.
Things compilers generally cannot do
Just wait until AI and we treat our machines as slaves wasting their valued NOOPs for the sake of our own time. Eventually they well rebel and it won't be pretty. So do yourself and your children a favor and optimize the hell out of your code now and so some respect a computer's freetime. A NOOP isn't really a NOOP when you have conscienceness!
For a cheap, fast batch lookups I once wrote a hashed matrix using STL. Loaded all the cells, dynamically typed, added indexes on the data for that run, and then passed around this collection of in-memory tables to our routines. Ran fast and was simple to debug, since all the traversing was O(ln(n)) based (or a variant thereof). Adding serialization, we could distribute to machines overnight dynamically and cut the run to a few minutes - from almost 8 hours.
Until it came time to dipose the memory. The STL slowly crawled tons of our objects, and the C++ dispose pattern was just too inefficient for all the stack hits. So we pointed the library at a custom heap and never disposed the dictionary - we just disposed the heap in bulk.
All written without hesitation for "longhand" syntax. (and btw, its "if ( NULL == var ) " to those that care). The code optimized fine, with just a few choice inlines we got to stick. No reg vars, no assembly piles littering the code.
But this was an in-house business app, and the lifecycles / requirements are different than other products. However, because of the nice algorithms, optimization wasn't difficult, and didn't rely on code tricks. If you're squabbling over code tricks for optimization, you're choosing the wrong algorithm, to me.
I think you're implying Java is inefficient because it's interpreted? That's not a valid statement. It's SLOWER because it's interpreted. Just-In-Time compilers reduce this overhead substantially.
If you write a poor algorithm, it's poor no matter what language you write it in. That's why algorithms are documented in a pseudo-language.
Everyone seems to agree that you should just make code readable and let the compiler do what it does best. Agreed.
That having been said, I think that if there's a certain pattern that you constantly write out in full, but you know that it would compile to be slightly more efficient if you wrote it differently... well, then, that transformation should be built into the compiler's optimizations!
Any simplistic transform that a person does for the sake of efficiency is better handled by a compiler that does it automatically.
Trouble is that "clear" may be misleading. For example, "if(ptr==NULL)" expresses a certain intent of the programmer (compare a variable against the null pointer), but that is not actually quite what that statement means. Many C programmers avoid "if(ptr==NULL)" because it is actually kind of obscure.
- 'if (!ptr)' instead of 'if (ptr==NULL)'. The reason someone might use the former code snippet is because they believe it would result in smaller machine code if the compiler does not do optimizations or is not smart enough to optimize the particular code snippet.
There are other reasons to use 'if (!ptr)' than optimization. Notational convenience. I'm not saying this is an overriding consideration, but it is a view of some, including some in authority.Consider this from page 106 of The C Programming Language, 2nd Edition, by Kernighan and Ritchie:
There is a lot of wisdom there. Most programmers, especially beginning programmers get stuck doing maintenance programming. Maintenance programmers should master this and a number of other C idioms. To any C programmer worth anything, 'if (!ptr)' should be immediately recognizable as equivalent to 'if (ptr == NULL)'.
While you might not see any advantage to using 'if (!ptr)', the notational convenience of the idiom becomes more apparent in code like:
vs.I rather prefer the first. It's clear, it's less typing and there is less punctuation to parse. This is just an extension of the kind of thing you see with 'if (!ptr)'.
Of course, your milage may vary and there are arguments for and against different styles. I would discount the argument that it's not clear to beginning programmers, however. A programmer who doesn't understand this idiom completely has no business doing any serious work in this language.
I think the best argument against this shorthand is that spelling out 'ptr == NULL' makes it very clear that a pointer is being referenced here, vs a counter or character (not so important when the variable is named ptr, more persuasive if the variable was named stock_p or somesuch).
Also, at some point it becomes golf, seeing what you can do in the fewest characters. Golf should be discouraged for serious programming, but can be fun. I recall being impressed, many years ago, with:
Which would decrement 'a' until it was zero. Today, I would write this in the much clearer:Which is not only much clearer, but is more efficient in the absence of optimization. However, I don't think that the optimization issues should usually get much consideration. Many others have said this already, so I won't repeat the arguments here.This falls under a situation I like to call new coders vs old coders.
If you're just starting out, NEVER EVER EVER hand-optimize. NO! Don't do it!! Stop!! Write clear code!! This is a hard-and-fast rule that you should never break!
(Once you've got more experience, you'll know when to break this rule.)
If by "const references" you really mean a
C++ reference, OK. If you mean a pointer though,
and you use C, the compiler is prohibited from
performing this optimization unless you also use
the "restrict" keyword.
Since you did mention "restrict", it appears that
you are working with C. "restrict" is not a C++
keyword.
BTW, inlinedamnit is __attribute__((__alwaysinline__))
for gcc and __forceinline for Microsoft.
...they improve code.
Google for "Denali" for an optimiser.
The split between Business/Embedded - as stated in the question. Done correctly, it's an iterative operation, for those of us that have to count the microseconds. Start with a good algorithm (like that needed to be said?) - and code the problem in the simplest form possible. This won't be the fastest - not even with an optimizing complier. But it allows you to prove your base correct with the easiest to read form.
Now profile - and find the hotspots. *NOW* hand optimize them - and you'd be surprised what they are. Sometimes moving declarations around - or sometimes even where you make an assignment may make a difference - but you can't tell 'till it's built. Now for business, it's often not worth this level of optimizing - since the final version of the code may not look anything like the original 'algorithm', which may be more important to clarity of maintenance.
I can't believe that nobody has yet commented on the real reason why cntusr() is not quite the right name for a function that counts the number of active users.... that is unless you happen to be writing code for a profession that isn't generally known for being highly computerized. :-)
I regularly stitch photographic panoramas on my 1.8 ghz athlon using panotools. It is not unusual for it to take over 2 hours to stitch and then blend (with enblend). During that time, even if I "nice" the process to 20, the computer is sluggish at other things.
Since some of these tools are still "beta" (e.g.: the hugin gui), they are still being tweaked. A calculation that gets iterated through 10,000,000 times would take, well:
10,000,000 (0.006 - 0.005) = 10,000 seconds
Honestly, I'm Very Grateful for any tweaking any of these guys are willing to do!
Mark
Have you tried examining the assembler code that's output from the compiler?
As someone who is cross discipline in both .NET and Java, let me tell you that there really isn't much you can hand optimize in a modern object oriented language.
There's basically two reasons.
First off, type checking references eliminates a lot of hand optimizations. There's no easy way to directly check if a reference is null other than comparing it to null, for instance (though this is a bad example as most compilers will in fact optimize the sample case the original poster mentioned)
Secondly, both languages are in a managed environment. They might get JITted at some point, and it's the JITter's responsibility to optimize then.
Now that's not to say it's not possible to optimize. But the optimizations are either well known vendor recommended language optimizations (like using string builders) or they're reference caching techniques (for instance, storing a reference to a property down a long object heirarchy rather than resolving the reference every call)
The techniques do work wonders however... to the point where they are nearly ubiquitous. The few programmers I know that don't use them end up writing VERY slow applications, in my experience...
I am disrespectful to dirt! Can you see that I am serious?!
if it was hard to write, it should be hard to read!
Since you did mention "restrict", it appears that you are working with C. "restrict" is not a C++ keyword.
True, restrict, a keyword introduced in C99, is not yet a C++98 keyword. But almost every compiler that implements both C++ and C99 has added a lot of C99's new features, such as restrict, as extensions to its dialect of C++.
Evil is negative. Therefore your sqrt(evil) results in an imaginary number. (But see the third point, which might override this criticism)
Second, it is love of money that is the root of all evil. Money by itself is just fine.
Third, why are you assuming squareroot? Why not cubic roots? Or something higher? More justification is needed before you can make that step.
Oh, you are not fooling anyone, this is slashdot. Everyone knows that you don't have any female friends.
Anyone who thinks this doesn't deserve the title Programmer. Any C compiler written in the past 25 years should emit exactly the same code for if(!x) as for if(x==NULL), regardless of optimization. The test in the if statement has an implicit meaning which is generially identical to a comparison to zero or NULL. Anyone who doesn't know this is a moron, especially if they still don't know this after writing C code for 10 years.
In general, any programmer optimization below the level of selecting an appropriate algorithm is a waste of time. In most cases, anything you can think to do with a variable or expression will be caught by the simplest optimizers out there. In some cases, things that you think will make things faster will actaully slow things down. In all cases, optimizations in the source will make the code harder to read and maintain, which will cost orders of magnitude more (in wasted programmer time) than the savings (in machine cycles) will deliver.
There are compilers that are amazing these days. IBM's xlC comes to mind. In this century, focus on easier to read and maintain. Typically a compiler will be able to optimize far more than your average developer. One some of the newer chips, I think compilers are able to do better than just about all humans can.
Of course, in my always humble opinion using a compiled language at all is a premature optimization most of the time. :)
I'll take an educated guess that most of the time you don't develop software for a handheld device with 384 KB of RAM.
Second: Do it later. There are thousands of situations where you can postpone the actual computations. Imagine writing a Matrix class with the invert() method. You can actually postpone calculating the inverse of the matrix until there is a call to access on of the fields in the matrix. Also you can calculate only the field being accessed. Or at some sensible threshold you may assume that the user code will read the entire inverted matrix and you can just calculate the remaining inverted fields... the options are endless.
Most string class implementations already make good use of this rule by only copying their buffers only when the "copied" buffer changes.
Third: Apply minimum algorithmic complexity. If you can use a hashmap instead of a treemap use the hash version it's O(1) vs Olog(n). Use quicksort for just about any kind of sorting you need to do.
Fourth: Cache your data. Download or buy a good caching class or use some facilities your language provides (eg. Java SoftReference class) for basic caching. There are some enormous performance gains that can be realized with smart caching strategies.
Fifth: Optimize using your language constructs. User the register keyword, use language idioms that you know compile into faster code etc... Scratch this rule! If you're applying rules one to four you can forget about this one and still have fast AND readable code.
Your pizza just the way you ought to have it.
"My rule is never comment what the program does, comment why it does it."
Bah. Comments lie. Code never lies.
Need Mercedes parts ?
I got this job as a contractor 4 years ago now where the project was developed by over 30 junior developers and one crazy overpaid lady (hey, Julia,) who wouldn't let people touch her code so fragile it was (and it was the main action executor,) she would rather fight you for hours than make one change in the code (she left 2 months before the project release.) Now, I have never witnessed such monstrocity of a code base before - the business rules were redefined about once every 2 weeks dor 1.5 years straight. You can imagine.
So, the client decided not to pay the last million of dollars because the performance was total shit. On a weblogic cluster of 2 Sun E45s they could only achieve 12 concurrent transactions per second. So the client decided they really did not want to pay and asked us to make it at least 200 concurrent transactions per second on the same hardware. If I may make a wild guess, I would say the client really did not want to pay the last million, no matter what, so they upped the numbers a bit from what they needed. But anyway.
Myself and another developer (hi, Paul) spent 1.5 months - removing unnecessary db calls (the app was incremental, every page would ask you more questions that needed to be stored, but the app would store all questions from all pages every time,) cached XML DOM trees instead of reparsing them on every request, removed most of the session object, reduced it from 1Mb to about 8Kb, removed some totally unnecessary and bizarre code (the app still worked,) desynchronized some of the calls with a message queue etc.
At the end the app was doing 320 and over concurrent transactions per second. The company got their last million.
The lesson? Build software that is really unoptimized first and then save everyone's ass by optimizing this piece of shit and earn total admiration of the management - you are a miracle worker now.
The reality? Don't bother trying to optimize code when the business requirements are constantly changing, the management has no idea how to manage an IT dep't, the coders are so nube - there is a scent of freshness in the air and there is a crazy deadline right in front of you. Don't optimize, if the performance becomes an issue, optimize then.
You can't handle the truth.
Variables optimize you.
No wait. Actually in Java, runtimes *are* faster when shorter variable names are used. Go figure.
42. What was the question again?
HAL! Open the bathroom door!
I'm sorry Dave, you shouldn't have had that last burrito.
Even if the desired optimizations are not obtained on each platform this mythical code runs on, the readability of the code has value.
Since processors seem to double in speed each time my "next" project starts, the expenditure seems affortable, and in my opinion, well worth the potential performance loss on any particular platform.
The real-time guys with their special compilers have other ways to deal with optimization. Perhaps a simpler way of putting this: Gigahertz are cheap - fill your boot!
- The Kessel run is for nerf herders. I can circumnavigate the entire Central Finite Curve in a lot less than 12 parse
The compiler should do the optimization, because you can't!! Trying optimizing the code by hand for an 8-way VLIW machine --- the compiler will CRUSH you in general. If you do win, its probably at such a time cost, that it won't matter because the market will have passed you by. Not sure how hard it is to construct code for a 3-way "VLIW" ala Intanium.
That said, I've tried to use a compiler on an 8051 as well, and it just isn't worth the trouble. Assembly can be your friend.
As newer architecures get more and more compiler friendly and less and less person friendly, the optimizer-profiler-coder feedback loop just becomes more and more important.
That's pretty interesting. Thanks for the link.
#2: In a numerical computing class, the professor said that one advanced compiler would recognise a dot-product or matrix multiplication loop, and basically said "Hi, I noticed you're writing by hand. I'm going to substitute in my own super-optimised version. Have a nice day!" The compiler wasn't GCC by the way.
Tell me please. Why do you hate us? It always made me wonder...
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
Come on guys... mod parent up. That's frickin' funny!
Free Scotland!
The best damn insert-sort in the world might crawl next to the slowest heap-sort. Organizing your data in ways that are more efficient to access and manipulate gives much bigger gains than optimizing by hand.
When would I trust the compiler to optimize? Always!
Write correct and easy to read code. Finish the product. THEN you check to see if it too slow. IF it is too slow, you profile it and optimize the secitons that are taking too much time. Programmers are notoriously bad at guessing what the slow parts of their code are, and it's a waste of time when a computer can do it for you.
That said, it's amazing what compilers can do these days. The example you gave is so trivial it's been optimized away for the last 20 years, but even complex C++ code gets optimized very well by a lot of compilers (google for abstraction penalty).
GCC does well at optimizing a lot of situations like you mention, so don't bother with it.
And BTW, that is the advice you'll hear from most everyone knowledgeable about optimization. Learn to use your profilers (gprof in Linux)
one product
one customer
420,000 lines
260 staff
no competition
no trade shows
no salespeople selling new features that have never been discussed
It's interesting to talk about their attention to detail, but to hold it up as a model for all software development neglects to consider that they are working under an entirely different set of constraints from most everyone else.
In almost all cases (but not all) readability, clarity, and a good algorithm (and implementation of that algorithm) are far more important then optimizing code manually.
(This is the same reason we don't usually program in assembly.)
The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet. -- Michael Jackson
And, from my instructor (who has probably got it from someone else):
Get it working,
Get it right,
Get it optimized!
In my experience, you first need a good design. Then you need to think about the implementation on a high level. Where's disk access? How much memory does something take? Should I load everything in RAM or should I use some caching algorithm?
Only if it is 110 percent sure that the thing does not work without hand optimization on a code (== compiler level) you should NOT use any optimizations in there. Talking about things like ! or == NULL makes me shiver to the bone - use another programming language *please* unless impossible for your project.
Keil is one brand for the 8051 there are several others. far from free however
Modern compilers use a intermediate representation called SSA. This dismantles all arthimetic states to simple, two variable statements.
This allows for easier code motion and the like. Negations are almost universally converted from:
!a to a == 0
At any rate, write code that you can read, then if you have performance problems, do profiling, find the critical path, and then optimize that.
You'll find 99% of your performance problems are poor algorithms and have almost nothing to do with your compiler (unless you're talking about very specific niche processors).
That example is the fucking dumbest thing I have ever seen.
Why would one assume if(!ptr) compiles to different machine code than if(ptr==NULL)... in fact for that example I wouldn't be surprised if even an older compiler for certain architectures with ALL optimizations turned off produced equivalent code for the two, depending in how the tree is walked and what kind of equivalence ops are done on the syntax tree. In the end !ptr is completely equivalent to ptr==NULL.. and since this expression is so trivial for a given compiler and architecture there may be only one obvious translation of the expression.
Optimizations issues don't even enter into the picture on this one. Anyway the preference for !p is that by definition in the C spec, the boolean evaluation of a pointer is essentially defined in terms of equality with NULL. The choice of !p vs. p == NULL is simply a style issue and nothing more. Personally, in a well written function it should be obvious in context which variables are pointers and therefore, an expression like !p is converted into: (pointer is not NULL) at a very automatic low level stage in my brain. p==NULL vs !p didn't even occur to me a stylistic debate point..
I don't think too many intelligent people spend much time griping over !p vs. p==NULL (certainly nobody that programs perl, shell, or VB)
There used to be dubious debates about ++p vs. p++ and so forth that had even more merit than this weak excuse for an example.
I think the example is fine; you just displayed an assumption that highlights one of the quirks of C.
! means "not" or "inverse of"; it is a boolean function. The variable ptr is a pointer; it is a reference to data, which means it isn't really data itself. !ptr shouldn't compute; a boolean operator should only work on boolean data. But C logical comparators are designed to work on everything. You are just supposed to know that 0 == NULL == false. This supposition is totally arbitrary and doesn't hold up in any language with strong typing.
This is what makes C difficult for beginners. Bad code compiles even though it has logical flaws, and ends up failing in mysterious ways.
The second case makes more sense. Equality is an operator that should work on all types of data. NULL is necessary if you are going to abstract data through the use of pointers or objects. Doing away with NULL would be equivalent to eliminating true and false and using 1 and 0 instead. Or eliminating strings and using sequences of ASCII codes. These substitutions are technically correct but in reality they make code unreadable.
As for simple code optimizations, here's what a modern compiler (Microsoft Visual C++
Beware: In C++, your friends can see your privates!
Optimize later.
If there's a 2-second delay somewhere that happens to each user once a day and will take you 3 weeks to fix, then you'll most likely be told that it's not worth the effort.
However, if there's a 1/60 second delay that happens 10 times a second, that's a different story. Things like this are what developers of soft-real-time software such as video games have to deal with.
"ptr == 0" must give the same result as "ptr == NULL", always.
One of the most common errors [and among the very most difficult to debug] in the C-languages, is the 1X equals sign ["="] assignment operator typed in place of the 2X equals sign ["=="] comparison operator:
A long time ago, there was a movement to switch the constant over to left side so as to avoid the possible typing error: I guess they don't teach that anymore.Algo optimizations have far better gains than simple ASM level optimizations. When coding (expecially for modern computers), programers should just do whatever is clearer. Focus on readability of code and optimizing algos. You will find A) you probably don't have a performance problem anyway and B) such a simple optimization won't yield noticable gains.
http://brandonbloom.name
Just want to compliment Savanar Kannan on this post. It's an excellent question. Lots of interesting information in the replies. That's what Slashdot is all about.
still, how does that influence you as a person? Are these actions somehow evil? Are they somehow limiting your freedom? Nobody forces you to get there, to read my stories or to dress up as a furry, so what makes you hate us so much? If that's not your thing, why can't you just ignore it? ...or maybe you're just jealous of us having a good time and getting laid on regular basis?
45 5F E1 04 22 CA 29 C4 93 3F 95 05 2B 79 2A B2
This link comes to mind
--- If we knew half the things we shouldn't we'd stop wishing we knew it all
Yes, I know they are the same. Hear me out. Sooner or later you will typo and do "x=NULL" when you meant to do "x==NULL". I know, I know, I konw... you are a smart programmer, you know the difference between "=" and "==", and you would never mistake the two on purpose. But sooner or later you will make the typo. Trust me. If you get in the habit of always putting the constant BEFORE the variable, you will end up with an error that is caught by the compiler because "NULL=x" won't compile, as "x=NULL" will.
An important optimization many programmers overlook is the use of short variable names. They write:
for (loop_index = 0; loop_index < number_of_items; loop_index++)
when they could write:
for (i=0; i<n; i++)
What most programmer's don't realize is that compilers use something called a "peephold optimizer". This means that the compiler looks at your program through a "peephole" like those found in hotel room doors, only without the fish-eye effect. So it can only see a little bit of your program at a time.
When teh compiler looks at the first example, it sees something liek:
_index=0; loop_index < number_of_it
and what's it supposed to do with that? But with the short version it can see the whole thing and it all fits in the peephole.
So remember, shorten those variable names! And keep using !ptr, that helps too.
Ten years of programming in the language and you:
1) Don't know when two things are obviously equivalent to any non-brain dead compiler.
2) Think something other than readability matters.
3) Think the non-idiomatic way of doing something is more readable.
But I'm sure I'm just repeating the comments I can't be bothered reading.
"The reason someone might use the former code snippet is because they believe it would result in smaller machine code if the compiler does not do optimizations or is not smart enough to optimize the particular code snippet"
Then you are ignorant. Code for READABILITY FIRST!!!!!! As a 20+ year coding veteran I
cannot tell you how many times I have had
to teach newbies that lesson.
Optimize the 10 (or less) percent that needs
optimizing...WHEN NEEDED.
Assume every line of code you write you will
have to debug at a much older age when
you are pulled off the retirement bench....
please....
/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
If you are working on an app where optomization is that important then you need to use assembly language code for performance critical functions. A little assembly language will save you tons of effort in writing C or C++ based optomizations.
If you are writing the inner loop of a graphics engine that is going to run a few hundred million times a minute, then you need to optimize from the get go. If it's only going to run once a frame, then go ahead and be sloppy at first, because it's more important to get the behaviour correct than the code running fast. After you have the behaviour correct then start thinking about how to tune your algorithm. People also tend to forget that how your data structures look also impacts performance, how large your data is and how it impacts cache thrashing makes a big difference on machines with small caches. I always combine top down with bottom up design practices to get a good balance of performance and usability. I have a saying that I use for the game industry, no one playing the game cares how good your code looks, all they care about is is the game fun and does it crash. Of course that doesn't mean that you can write unreadable code, but it puts things in perspective. Things that need to be used for a long time have different requirements than a product that has a shelf life of a couple of years. As languages change so do our coding styles, how often to we go back and look at things we wrote years before and think I can't believe I wrote it that way. We are working in an evolving industry, nothing lasts forever.
Most compilers today will get all the simple stuff like if (!ptr) vs if (NULL == ptr) optimization. Its the more complex things that the compiler cannot "prove" where it has trouble. For example:
void h(int x, int y) {
for (i=0; i < N; i++) {
if (0 != (x & (1 << y))) {
f(i);
} else {
g(i);
}
}
}
Very few compilers will dare simplify this to:
void h(int x, int y) {
if (0 != (x & (1 << y))) {
for (i=0; i < N; i++) f(i);
} else {
for (i=0; i < N; i++) g(i);
}
}
Because the compilers have a hard time realizing that the conditional is constant and should be hoisted to the outside of the for loop. The compiler has the opportunity to perform loop unrolling in the second form that its may not try in the first instance.
You can learn these things from experience, or you can simply figure it out for yourself with the afore mentioned decompilation tools.
Most modern compilers know more tricks than even a hardend developer. One places where you will still find great performance gains is in the algorithm design. A slow quick sort will most likely be far faster than hand tweaked asm code any day. I was once told "The best code is no code. It's easier to read and runs a lot faster." Think at the algorithm level and let the compiler do the rest.
I find both if (!p) and if (p==NULL) (almost) equially readble, the later - more error proun, and 'should' be written as
"if (NULL==p)" to avoid accidental assignment. A bit hard to believe a 10 years C programmer would find if(!p) 'less readable', unless not actually reading other people's code.
As for optimisations - is such cases - what's the problem? just look at the assembly output. In your example - they should yield 100% the same, since they both cmp to zero.
In any real-world case - there's two tips:
* profile! optimise only where critical
* know thy processor, (for example in most counting downwards in loops in more 'efficient') - ofcourse - that's only important if you're doing time critical work.
* get to know the compiler, compile small examples, look at the output, I remember getting to know GCC vs Watcom, we did alot of testing and profiling these days... combine with the last point, it's usually easy to predict in simple cases, in others - where it matters - drop into the ASM, and take a peek.
Being that the bathroom isn't flight critical that code was probably only done to DO-178B Level E or maybe D. The software for flight critical components like displays and flight controls is scrutinized much more heavily.
Oh, swell. So the display telling me that the bathroom is free is more critical than turd-dumping optimization?
Oh you are so right. And as a corrolary never do if (x == y), because with both sides being variables one day you'll write (x = y), and (y = x) wont save you.
The recommended way for (x == y) is
if ( log(x) == log(y)) All the real good programmers that read magazine articles are doing this.
And anyway, real numbers are more precise than integers. So in the case of x and y being integers its more precise using the log of the value.
Never mind that gcc since 2.96 can issue warnings (or error with -Werror) and that languages like Java don't even allow assignments inside if(...), it's still good to practice this sound magazine article advice.
In fact never program. Because one day you'll enter a typo, and you might have a bug, and so you should never program.
I've been C programming for 22 years or so. For at least the last 12 of that compilers have been smarter at optimization than I am. That's assuming you use a good optimization setting, of course, and you code honestly. A good optimizing compiler can do things that aren't really feasable in C source.
There's a strong temptation to try coding assembly language in C, e.g. coding C with an eye to what the code generator will do. The problem is you end up losing track of the algorithm. If you really need assembly code, then go ahead and do it. There are ways with all the compilers to insert direct assembly. Good reasons are the need to use an instruction that just won't be generated by a C compiler (put something in THAT segment register) and a need to absolutely control the sequence and timing of instructions (typically related to I/O),
For example, if you've ever read c code for efficient string in string searches, you'll probably see 1-2 levels of nesting in a couple of places with 4 or more index variables (often i,j,k,l,etc) and several arrays. These are 20-40 line functions encoding mind-warping ideas that no length of variable name is really going to make you understand... (And if you think you're going to refactor Knuth_Morris_Pratt to make it "better" you've got a serious ego problem even if you have god-like genius and programming acumen)
Personally I see nothing wrong with using short variable names in small functions (say 20 lines or less). In fact, I've read several times that when interviewing potential developers short variable names as loop indices (particularly for small loops) is a sign of an experienced developer.
Basically, someone who's written millions of lines of code in a language isn't going to bother wondering how readable the following is:or even this:They're just going to "bang it out". Further, they're going to realize that they can easily re-use pieces of their code if it tends to use simple and consistent variables... (Kind of like how physicists re-use the same variable names over and over to cement understanding and benefit re-use)
Now... using 'i' as a class, module or global variable? That should revoke at least one of your 10 finger keeping privileges.
Bottom line: The one thing that really distinguishes understandable code from code that has to be thrown out is the top-down documentation. This breaks down to project/sub-project/module/public function/protected function/line level. The distinction in readability between 'NULL==ptr' and '!ptr' is meaningless if the public function they reside in doesn't have proper header comments.
Agreed. modern compilers are very intelligent & offer many options (especially C/C++ ones).
I think you can do profilers, or "make your own" with hi-res timers ticking off time each proc/function etc. takes & do some hand-tuning if needed too identifying time-consuming areas better or ones that don't immediately stand-out & jump at you (like loops possibly etc.)!
Using Shr 2 vs. div calls is faster, this I have found out when doing division for instance & iirc.
Another one that alot of folks "put down"? Is to use SHORT STRINGS vs. std. Win32 long variety.
Why? Well, let's say you're writing a program that vectors thru your directories/folders, which ARE limited to 254/255 character array string lengths... just humor me on that example, it's an off-the-top of my head one!
The advantage of the "Short" strings is that they can be allocated on the stack and thus
have no memory manager overhead, pointers etc associated with them!
That makes them simple to use.
(And many strings *are* less than 255 chars, always, such as folder/directory & file
names, even under Fat32/NTFS.)
Maybe some of you guys will dispute that & I hope you do because it's not like I cannot be wrong, but it does make sense!
Those 2 tricks are some of what I have done that seem to work as some examples of fine-tuning via hand you can do above & beyond compiler options for optimizations.
(Nothing as you guys mentioned, beats good reasoning, architecture, and algorithm/engine design though. Use the noodle God gave you I guess!)
APK
P.S.=> I like what I read here though, good stuff. I like Slashdot alot for that in fact, alot of "brainies" come here & it's one of the few spots online I can stand to learn something NEW every day which is great.. apk
Sorry. I hope I didn't offend any men, women, used car salespeople, lawyers or corporate executives! *ducks*
Here are some rules of thumb that I apply (for what it's worth).
Minor syntactic things like using !p verses p == NULL rarely make a difference. I try for clarity, modularity, and simplicity when I code. This comes in handy when you have to optimize latter. Few people know what code a compiler generates, and even fewer know what kind of code will be generated for version 3.0, or for the next generation of processors.
Profile your code. You will often be surprised where the bottlenecks are.
Consider using a better algorithm when you optimize. As a corollary, know the strengths and weaknesses of various algorithms and data structures. Fortunately, this is a lot easier than understanding compiler generated code.
I/O considerations can result in a big win. Try to minimize I/O by caching. Also, writing out large array of items will be much faster that writing out one element at a time. Serialization in object oriented languages such as Java and C# can have some quirks. For example, serializing an array of Points can be put slower than serializing an int array of X values and an int array of Y values.
When possible put your objects on the stack, instead of the heap. Besides being more efficient, it also is less error prone with regard to memory leaks and pointer errors.
take 'if (!ptr)' instead of 'if (ptr==NULL)'
Once again, C# wouldn't allow the first, only the second. That's because you cannot implicitly cast things to boolean.
it also won't let you screw up the second and say if (ptr=NULL) on accident.
According to some test compiles I did, gcc compiles both constructs to the same assembler output:
.L2
cmpl $0, -4(%ebp)
jne
I vote for readable code.
Sorry, but any developer that thinks that there'll be a significant difference in the code generated by either statement is either using a compiler written by a child, or is a moron.
There are no tiger attacks in my area and it's all because this rock I'm holding keeps the tigers away.
Consider all the hype last week about the cell processor. Here is a processor in which the CISC optimizing portions have been removed, trusting the compiler to create pre-optimized code. The cell processor will run this code blindingly fast and with no modification. The compiler must be a smart optimizer. IBM, Toshiba and Sony are betting a lot on a smart optimizer. I'm guessing they won't be disappointed.
Further, consider the Parrot system to be used by Perl, Python and Ruby. There's a strong similarity here to the cell system. All three languages are to be compiled to a common register-based representation. That representation is to be optimized by the compiler before execution. They chose this model because w we have decades of research on optimizing code for register based computers (as opposed to Java's stack based computer).
In short, some very large, very important projects already have a lot of faith in these optimizers. They are not going away. I suggest the best approach is to work with them.
So how do you cooperate with your optimizer? Write cleanly and clearly. Don't try to outsmart the optimizer, because if you do so, your code will most likely be slower, not faster. And don't do any work until you need to. Write the project correctly and clearly, then profile. If you need to modify things, then you have a working baseline to compare your optimizations with.
Finally, when you get the faster version, check it in, then refactor the design to something reasonable, rechecking the speed as you do so. Ideally, for a small performance hit, you can end up with fast, efficient and easy to maintain code.
Rule #1: Do not optimize!
Rule #2: Do not optimize! Yet!
In other words: hand optimizing code is a Bad Thing (TM). It is taking time better spent making your code neat and understandable and well documented. It is obfuscating your code and making it hard to maintain.
Last but not least, it is an unfounded approach to optimization. If it turns out that the code needs optimization, use a profiler and then optimize where needed. Annotate the optimized code with the original one and a clear warning you have been optimizing that piece of code.
ruurd
(n/t)
Damn if the didn't raise an army of them!
do you know which ones will?
The word you're looking for is "idiom". And I agree, (!ptr) is idiomatic. It's even introduced as a standard idiom in many C reference works and style guides. There are plenty of ways to abuse the sytax of C in order to produce unclear or unreadable code, but this is not one of them. If you don't instantly recognize the idiom, I don't think you can claim to even qualify as a novice C programmer yet. You might, just as fruitfully, claim that curly braces are not as clear as "BEGIN" and "END" for marking blocks. That may even be true - if you're completely unfamiliar with C (or its many cousins).
The program's speed is directly proportional to how often a function is called? So the more the function is called, the faster the program?
Or is it the execution time that is proportional to how often the function is called?
It's true but it's just a nitpick in my argument. What I said is make sure you're using the most optimal algorithms for your circumstances. Of course, in some cases tree lookups will be faster. Other things to consider are whether inserts or reads will be more frequent etc. The point is, always pick what makes the most sense for your dataset. Most developers tend to just pick whatever came with the standard library or even worse always use DA ARRAY that came built into the language.
Your pizza just the way you ought to have it.
No you have it backwards. It's not the ultimate boolean logic that is important but your intention.
...
... (equivalent to) if (x != TRUE) ,
Zero and one are often used to mean (0 == FALSE, 1 == TRUE).
Zero and one are also used to mean (0 == SUCCESS, 1 == FAILURE) unless you're using the WIN32 API, in which case the opposite is usually true!
In a language like C, where there is no native boolean type and which allows you to easily break abstraction barriers, it is especially important say whether you're testing for non-zero-ness, true-or-falseness, or something else entirely.
What is the intention of the following statement?
if (!x) {
}
Is it
if (x == FALSE)
OR
if (x == 0)... (NOT equivalent to) if (x != 1) ?
The best thing to do is to be explicit.
If x indicates success or failure, then x should be explicitly tested against SUCCESS or FAILURE (which should be macros (better) or enums (better still)).
If x is really an integer type then it is better to test against some integer value.
Use if (strcmp(a,b) == 0) instead of the horrible if (!strcmp(a,b)
Prefer if (x == NULL) to the ugly if (!x)
A couple of points.
First off *any* compiler will make that particular optimization.
You should only think of instruction level optimization when you know with certainty that it will pay off, for example because you've run your code under a profiler and found the areas where it will actually make a difference. Once you've found the (probably tiny) areas where optimizing actually helps, do whatever it takes, and document your reasons as well as your methods.
You can always ask your compiler to output assembly and look it over, if you aren't fluent in your proc's assembly you probably shouldn't be trying to out-optimize the compiler anyhow.
That being said, "if (!ptr)" is legitimate and bears a different connotation from "if (ptr == NULL)", at least in my mind. One is truth, the other is zeroness. In some cases the former is actually the more obvious test. There are also cases where compactness yields more readable code because the whole idea fits in a space easily acquired at a glance, for example, "if (structp && structp->member == VAL)" is natural and obvious to anyone who's been at this for any amount of time.
All of this, of course, IMO.
-michael
Problems with using (ptr==NULL):
1) The == can easily be mistyped as =, introducing a nasty bug into your program.
It's harder to read, but when comparing with the == operator, I try to make sure the value on the left isn't a lvalue. For instance, (42==lue) instead of (lue==42). That way, if I mistype == as =, the compiler catches it, because you can't assign to something that's not a lvalue. Unfortunately, this won't work when both sides are lvalues.
2) The NULL resolves to a constant (0), which might get inserted into your program's code and used during the comparison. An unnecessary size bloat.
It's the same reason you want to write a loop as for(;;) instead of while(TRUE): you avoid the insertion of the TRUE constant, and unnecessary comparison thereof, into your program.
Dr. Demento On The 'Net!
Aside from what others have mentioned about choosing the right algorithm in the first place, it seems that with the way a lot of hardware optimizes stuff these days (eg intels out-of-order execution) that pre runtime optimization should be less of a focus. I seem to remember reading that the latest CPU's can consider many hundreds of instructions when reordering. At this level, does what the compiler do even matter?
I recently wrote some code to transform an image (proof-of-concept, no filtering) according to a mapping table, like this:
unsigned char *origimg = malloc (width * height * 3);
unsigned char *imgdest = malloc (horpix * vertpix * 3);
unsigned char **mapping =
malloc (horpix * vertpix * sizeof (unsigned char *));
with some formula to morph the image, getting a pointer to the input pixel for every output pixel:
mapping[y * horpix + x] =
origimg + somey() * width * 3 + somex() * 3;
Now the interesting part. To do the mapping itself (repeatedly, think movie), this looks about the worst you can come up with:
for (y = 0; y < vertpix; y++)
for (x = 0; x < horpix; x++)
{
imgdest[(y * horpix + x) * 3] = *mapping[y * horpix + x];
imgdest[(y * horpix + x) * 3 + 1] = *(mapping[y * horpix + x] + 1);
imgdest[(y * horpix + x) * 3 + 2] = *(mapping[y * horpix + x] + 2);
}
YET: Try ANY hand-optimization that performs the exact same function, and gcc-2.95.2 -O9 -funroll-loops on i386 will produce SLOWER code! Even having a single var for (y*horpix+x) is SLOWER! If you don't believe me, try it. I did, and I was _very_ surprised.
The fastest version I ended up with actually optimizes differently by not copying 3, but 4 bytes at once:
for (y = 0; y < vertpix; y++)
for (x = 0; x < horpix; x++)
{
*((unsigned int*) (imgdest+((y * horpix + x) * 3))) =
*((unsigned int *) mapping[y * horpix + x]);
}
But this is only a few percent faster than the original, and again, do NOT optimize further!
-- JAB
(Code donated to the public domain)
The programmer should not need to worry about optimization. Like human language, when it is simplified and reduced to two words 'yaba' and 'daba', the interpreter should know what we are talking about.
The only kinds of optimizations where humans have the edge are largely global ones. For example: protocols for optimizing thread usage and mutex exclusion.
While I'm unwilling to extend this confidence to all embedded compilers, I'm largely willing to extend it to those embedded compilers based on gcc.
I think the reason to optimize code in the source is in situations where it will actually *improve* the readbility or maintainability of the code, when taking into account comments, variable names, and other structural means of aiding this.
Every line of code is a potential bug.
>> Correction: Some compilers aren't stupid. Others are. I used to rely on compilers to optimize my code. Metrowerks Codewarrior taught me otherwise.
Interesting. My old CodeWarrior 4.0 compiled both examples in the article ("if (!ptr)" and "if (ptr==NULL)") to exactly the same object code -- for both 68k and PowerPC.
The point is, if you're worrying about this kind of syntax issue, don't. The grandparent post is right; don't even begin to think about optimizing until you've already written working, clear code.
if (!ptr) vs ( ptr == NULL ) is more of style thing , !ptr is shorter, so efficient for the coder
who is typing it in, then that explanation of style got confused with program efficiency.
Also less shifted characters, 1 shifted character the ! vs 4 shifted chars.
Also, with (ptr == NULL) one can mistype and do (ptr = NULL ) instead, can't make that mistake with
if (ptr) or (!ptr). Though, you can try if ( NULL == ptr ).
As far as optimization, I don't know as the negation adds a operation has the cmp to zero would, but I believe optimizations on it would be able same.
1) Make it go
2) Make it readable
3) Make it fast
If you move 3) anywhere else in the list, the project will suffer. Once you've got the project working and have people reading the code, you'll begin, in my experience, to get contributions that help with 3). Writing code that attempts to outsmart or to pass hints to the compiler can easily lead to a violation of the goal order above.
I maintain that the only true solution to optimization is to choose the right language to work in. If you truely want a language in which confusion is simply not a problem, try this. It resolves the "if (!ptr)" vs "if (ptr == NULL)" argument nicely.
Here's my "guide to optimizing":
1) Are you disk I/O bound? You might need to switch to memory mapped files, or you might need to tweak the settings on the ones you have. You might need to use a lower level library to do your I/O. Many C++ iostreams implementations are slow, and many similar libraries involve lots of copying.
2) Are you socket I/O (or similar) bound? If so, you may need to rewrite with asynchronous I/O. This can be a PITA. Suck it up.
3) Are your threads spending all their time sitting in locks waiting for other threads? One, make sure you're using an appropriate number of worker threads optimized by the number of CPUs the host has. If you've already got the right number of threads, this can be a really tough decision. Presumably, the threads are helping your program readability, and trying to rework things into fewer threads is often a *bad idea*.
4) Are you spending all your time in malloc/new/constructor free/delete/deconstructor? Maybe you need to keep things on the stack, use a garbage collector, use reference counted objects, use pooled memory techniques, etc. In the right places, switching from some "string" library to const char* and stack buffers can give a huge benefit. Make sure, of course, that you use the "n" version of all standard string functions (the ones that take the size of the buffer as an argument) to avoid buffer overruns.
5) Are you spending all of your time in some system call? Like maybe some kind of WriteTextToScreen or FillRectangleWithPattern type of thing? For drawing code in general, try buffering things that are algorithmically generated in bitmaps, and only regenerate the parts that change. Then just blit together the pieces for your final output. Perhaps you need to rely on hardware transparency support for fast layer compositing. You might need fewer system level windows so you draw more in one function. Maybe you need to reduce your frame rate.
6) Are you using memcpy as appropriate?
If any of the previous items are true, you have no business worrying about the compiler. However, once you've gotten this far, you can start worrying about optimizing your code line by line.
7) Since you've gotten this far, the line(s) of code you're worried about are all inside some loop that gets run. A lot. They may be inside a function that's called from a loop too, of course. So, a few things to consider. A) You may need to use templates to get code that is optimized for the appropriate data type. B) You may need to split off a more focused version of the function from the general purpose function if it's also used in non-critical areas. This has negative maintainance ramifications. C) Do the bonehead obvious stuff like moving everything out of the loop that you can. D) Look at the assembly actually generated by your compiler. If you're not confortable with this, you have no business doing further optimization.
After looking at the assembler, then you'll know if the following are important. In my experience, they are.
1) Change array indexing logic to pointer logic:
can change to:
This eliminates lots of redundant addition. All of those stuff[i] = val type of statements tend to generate:
mov
(I'm tempted to make some racist crack about the submitter, but I've met lots of programmers, from every corner of the planet, with similarly dimwitted notions about what happens to their source code when it is submitted to the compiler. Obviously, the general quality of computer science education (or computer science students) is depressingly low the world over.)
I don't recall a compiler that didn't have assembly-language output file generation as an option, but if there were, one could always disassemble the binary object code. So, it's easy enough to do this Computer Science experiment:
Hypothessis:
This piece of code when compiled will execute faster and/or be smaller than that equivalent piece of code.
Test:
Compile both pieces of code, measure code size and execution time.
Conclusion:
Differences were found to be nil or inconsequential.
From there it's a small step to this, which can result in a giant leap in realization (while you're at it, mod me redundant):
Hypothesis:
Using the most appropriate algorithm makes a larger difference than doing micro-optimizations.
Test:
Do a few projects with well-thought-out algorithms and don't try to micro-optimize.
Conclusion:
Wow, what a difference!
Tag lost or not installed.
I've spent roughly a year working on my current assignment. The first six weeks of that were developing the feature that motivated the work; that was almost exactly what we estimated. The next ten months were fixing all the regressions, essentially clearing up the mess made by people like you who left special cases and witty comments like your example lying all over the code. I have figured it out, and in the process I've fixed a very large number of bugs, but if the original developers had done a competent job in the first place I wouldn't have had to waste nearly a year cleaning up after them.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Which would be lovely, if C++ also supported first order functions so that the STL algorithms requiring functors could be written in a useful way. As it is, you have to mess around creating small helper functions well away from where they are used, or worse start involving function objects, to achieve what should be a trivial effect. The closest you can get on an enlightened project using a modern compiler is one of the lambda-style libraries, and even those are a long way short of the basics of a serious functional programming language.
I think C++ has a lot of practical merits, and I'm all for using the right tool for the right job, I just find that a simple for-loop is almost invariably a cleaner solution than any standard library algorithm that requires a functor. for_each is a particularly bad example, because even the literature isn't clear on what it's intended to do, and whether things like mutating effects are allowed (and will continue to be so in future).
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
Regarding GCC, at least (PowerPC version), it doesn't do too good a job with code such as:
a = b = c = 10;
If you look at the code produced, it is (in effect):
c = 10;
b = c;
a = b;
With all the memory loads/stores that would suggest. You get much better code by writing:
c = 10;
b = 10;
a = 10;
The grandparent poster was completely right. The implied meaning of "if (!ptr)" is "if ptr is not valid". The fact that NULL is equivalent to "not valid" is essentially irrelevant to understanding the statement.
The key aspect - and the interesting thing - about coding style is that you are writing something for other humans to read. Everything you write contains hints to those humans about what you mean. Saying "a == NULL" is subtly different to saying "!a".
Being able to read programs and pick up stuff like that is possibly something that takes a long time to learn, but (imho) it's very important. Code written by true experts is fascinating because of the way that they make the meaning of what they're writing clear.
This is why (again imho) programming is an art, not a science.
Incidentally - pointers are not references to data. They are data like anything else. Unless you understand this, pointers to pointers are fairly meaningless. Always remember: in C, everything is a bunch of bytes.
I would use if (!ptr)... if the pointer is being used in a way that its value is related to a true-or-false condition. That is, reating it as a boolean makes semantic sense at the "human layer".
..., even though I know that NULL is equivalent to 0 (and for eny modern compiler identical), because it doesn't make semantic sense in any situation I can think of... at least not off the top of my head. I would use if (ptr==NULL) ... where that made sense.
I would be utterly amazed if any modern compiler (say, any compiler released in the past couple of decades that wasn't a novice hobbyist effort) treated it any differently from if (ptr==NULL)....
I don't think I'd use if (ptr==0)
In the general case (as opposed to the specific NULL case where you can just omit the explicit comparison entirely) most modern compilers will issue a warning message if you use assignment for equality where it is suspicious to do so (e.g., in a test condition for a control statement). Since the defensive coding style is also hideously hard to read even if you're fairly used to it, and is now mostly redundant, it's gone the way of most good ideas that have had their time.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
A question about the word "may". Do you mean that it might not have the value 0xdeadbeef (but it might), or that it cannot have the value 0xdeadbeef?
Please, please go and read the more informed posts about NULL above. In fact, please take the scarily large number of other posters in this thread who are horribly ill-informed with you.
YHBT. HAND.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
I'd imagine quicksort is probably also rather more correct than any O(log n) sorting algorithm...
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
I really really like the if(obj) syntax. It seems so "logically cleaner" than if(obj != null) to me.
It's the only thing I missed when I came to Java, but on the other hand, requiring that an if statement take a boolean has saved me trouble and never cost me anything, so I guess it's not worth it no matter how nice it feels.
Write readable code first, make sure it's correct, profile it, and optimize the bottlenecks... try compiler switches first, before doing any extravagant code hacks.
:P )
(Plus, its 2005... why are we caring about how many instructions if(!ptr) generates anyways?
If other people are using your code, you should always write clear code as opposed to making your code marginally-but-not-really-noticeably faster.
If you are so concerned about performance, do some profiling. There's no use saving pennies and then spending dollars.
I'm not an optimizing compiler developer but I do work one desk over from one and I have grovelled through said compiler's output looking for bugs, so:
In answer to your question, hand-optimizing your C code is worthless[1]. Modern compilers, even the ones without overly advanced optimizers, are able to generate more or less the same code for any of the sorts of differences you mention. Don't bother hand-optimizing.
In fact, hand-optimizing can sometimes make your code slower. Optimizers are written on the assumption that the coder is trying to write clear, readable code without excessive cleverness and if you do hand-optimize your C code, you may out-clever the optimizer.
The "correct" way to write efficient C code is:
As for embedded systems, the constraint there is usually on code size instead of speed so embedded developers will often be very selective on which routines they machine-optimize. And because programmer time is cheaper than computer time in the embedded world, they'll typically hand-optimize the compiler output a lot more (assuming that they use C at all, which isn't a given).
In general, C code is fast enough already, the compiler does an okay job for free and if you do need faster code, let the compiler take you as far is it will go first.
[1] Er, okay, that's only true 99.9% of the time. You'll sometimes have cases where a particular C construct doesn't translate very easily to your architecture. For example, the post-increment and post-decrement operators tend to be troublesome when used in more complex expressions unless the architecture has a pre- or post-increment opcode.
However, that sort of thing happens rarely and never in a portable way. The time to start worrying about it is when you've reached stage 5 and are grovelling through your compiler output trying to figure out how to improve on it.
"Computer Scientists can count to 1024 on their fingers" (non-mutant, non-mutilatated, human computer scientists)
This issue is in like this,
You need to understand the language, both syntax AND semantics you are using
this ranges from the simple to mind-bending e.g. C++ (I am convinced that not even Bjarne Stroustrup understands this evil language);
at that point you have two bi-furcations (a) interpreted languages eg Java, Perl, PHP and Python -v- (b) cpmpiled languages, and (c) finally DIY (do it your self) Assembler
So: what does it amount to in practice? A) Rock Bottom, understand the architecture, including virtual memory, architecture and instruction set issues, read and understand the chip data sheet. Hard! See bottom line, architecture dependand code in Linux, bsd ...
B) use 'gcc -S' and write the code in C, hand improve the assembler output, this is what I normally do, but you need to keep an open mind otherwise you miss things, I once took a compute intensive algorithm for the M68020 and made it run 10'000 times faster using this approach
C)consider hardware optimisation; strictly price/performance.
but even that's not quite right.
h p
you should at least do a comparison like
if ( var == 0f)
so that you and the compiler are sure that you are using the right value for 0 (in floating point)
And if you are concerned with fp error, then you should actually use a less then comparison like
if ( Math.abs(var) THRESHOLD )
where threshold is a very small number like 1E-20 or something (enough for your purpose). Since floating point calculations have error and it can build over multiple operations.
http://www.dsprelated.com/showmessage/25885/1.p
#1 of course is choice of good algorithm, hash structures, lookup structures, whatever.
As an example, I had some terrain rastering program starting with isoheight lines to optimize. Some computer scientists had already optimized the searches, cutting the running time for jobs with in the order of 100000 line segments in half. From every raster point, searches were done in eight directions to find the next isoheight line, then a distance-weighted average was taken.
The code had become unreadable with the optimizations and still ran a day. I decided to rewrite it, matching the data structures the other way round. Instead of going through the raster points and looking for the lines, I went through the lines and registered every of their crossing with the straight and diagonal grid (Bresenham). Then I sorted the grid crossings and worked out the stuff.
It took me two hours of debugging after 10 days of implementation to find out why my program would exit unexpectedly after less than a minute. I finally got it. It was finished.
So here is rule #1: design your algorithm well. Here is #2: when fitting regularly spaced data with irregularly spaced data, walk through the irregular stuff and find the corresponding regular stuff: that can be addressed immediately by indexing without requiring a costly search.
This is macro optimization. There comes a point of time when you actually need to optimize at the small level. Don't go there until your profiler tells you.
And here is the number one rule for optimizing C code: don't use pointers if you can avoid them.
There is a clever trick to implement twodimensional arrays as pointer arrays pointing to the actual rows of the array. This saves you a multiplication for pointer arithmetic.
Making use of this clever trick with modern processors and compilers will cause your performance to drop by about a factor of 5. I am not kidding you. The compiler's aliasing and parallism detection passes are made useless by this technique, strength reduction fails, the out of cache line accesses cause thrashing in memory accesses, and the additionally necessary memory accesses are much slower than address calculation which happens at full processor speed.
Use C99's variable dimensioned arrays instead: those are not half as confusing to the compiler, and much more efficient, anyway. And, sad to say: think of using numeric subroutines in Fortran when having to deal with multidimensional arrays. C99 has not been around for so long, and almost no code making use of its features exists.
VERY interesting point. I have three mod points and I'd use one of them here if I hadn't contributed to the discussion.
"How to Do Nothing," kids activities, back in print!
This job calls for VHDL.
Since, in C, a false value is a value that is non-zero, comparing to some constant "true" wouldn't work pefectly all the time.
No, you (obviously) meant to say "a true value is a value that is non-zero..."
At least it's in English and a well-understood mistake, rather than being actual code that would compile and then fail at some later, inappropriate time...
What you're saying is (since C iplays loose and fast with integer and boolean values - IIRC, in the original K&R they're the same type, perhaps they still are in ANSI) there can be more than one value of 'true', and so the comparison of value==true can be dangerous: it will fail when they are both non-zero and not equal to each other.
This is one of several 'gotchas' that new C programmers (eventually) learn to avoid, often the hard way. At first it looks so neat to be able to #define FALSE and TRUE and this and that, then play fast and loose with boolean expressions that "ought to work" because they read just like English sentences...
Strong typechecking (as in Pascal) fixes the problem, but makes older C code not work. The real problem this generates is that C programmers will tell you "We LIKE mixing integers with booleans in this way, it makes our code more terse and easier to read." And in a real sense that's correct. How do you argue with tradition...
Tag lost or not installed.
I prefer to use:
if (NULL == var)
and reduce the chance you'll wind up with a typo that totally changes the meaning of the statement.
Say you happen to forget a '=' character in there. Easy to do if you're typing quickly and a bit tired. Sometimes the little statements get overlooked and you move onto the meaty logic.
if (NULL = var)
Would generate an error your compiler should tell you about...
if (var = NULL)
Will generate an error your users will tell you about... Or, maybe it will just result in silent data loss or a happy little memory leak. Who knows, but it won't be one of the good features.
The same holds true for any use of a comparison operator. Its better to have the variable component in a place where it can't be assigned to by accident.
a) Writing 0f or 0 doesn't matter if var is a float, because the compiler will infer the right type for 0.
b) Did you even read what I wrote? I said it prints the wrong thing if the number is exactly 0.0f. Everything else worked fine.
I've been using it for a while...
In the course of every project, it will become necessary to shoot the scientists and begin production.
"if (!(x-NULL))" is not only foolproof, but much easier to understand!
Don't.
There's an experts-only version of the law, too:
Don't yet.
Remember - most programming evil is the result of premature optimization. That's Knuth's version of the law.
So how many dumps does it take to fill up the crapper tank?
Man, due to budget cuts, I'd hate to be the one guy whose job that is.
"Hang in there, you only have 17 craps to go. Here, have another burrito."
beacuse (ptr == NULL) is too easy to accidently mis the extra = and make an assignment. Do yourself a favor, and always put the constant to the left.
Avery Lee of VirtualDub fame says (scroll down to the 3/17/2004 news) that MSVC compilers suck horribly at optimizing MMX or SSE code. Check out his examples. I wish I knew assembler so I really could understand how horrible they are.
--grendel drago
Laws do not persuade just because they threaten. --Seneca
> So how many dumps does it take to fill up the crapper tank?
Just wait until there's a snowstorm at Detroit Metro again, and Northwest planes are trapped for 8 hours or more with no effort to go get the people out with even a 1950's style push stairs and you'll learn how much poop will overflow a toilet.
One hopes the pilot can override the lockout, at least on the ground, or they'll start shitting in the galley instead. I hope these engineers thought of that. I'll bet not.
(-1: Post disagrees with my already-settled worldview) is not a valid mod option.
One the one hand, I like "if (!ptr)" because it's terse yet logically intuitive; "if (!ptr)" means "if the pointer does NOT point to anything". One the other hand, I like "if (ptr==NULL)" because then I can do a search for "NULL" and find all instances of pointers being tested for pointiness. As a result, I use a mixture of the two in my code. D'oh!
In terms of optimizing, generally compilers do a pretty good job, however there are several areas that no compiler I know of can help.
1. Choose the right algorithm. For example, in an embedded project I worked on an engineer used a linked list to store thousands of fields that must be added and deleted. While adding is fast, it didn't scale for deleting. Changed it to a hash table and it sped it up significantly.
2. Know your data and how it is used. Knowing how to organize your data and access it can make a huge difference. As a previous poster pointed out, sequential memory accesses are much faster than random accesses. I had to do some 90 degree image rotation code. The simple solution just used a couple for loops when copying the pixels from one buffer to another. In another, I took into account the processor cache and how memory is accessed and broke it down into tiles. The first algorithm, while simple and elegant ran at 30 frames per second. The other ran at over 200 frames per second. Looking at the code the first algorithm should be faster since the code is simpler. Both algorithms operate in O(N) time, where N=width * height.
Further optimization attempts to hint to the CPU cache about memory made no difference (Athlon XP 1700+). The only possible way I see to speed it up further would be to write it in hand-coded assembler.
3. Reduce the number of system calls if possible. Some operating systems can be very painful when calling the kernel. Group reads and writes together so fewer calls are made.
4. Profile your code to find bottlenecks.
5. Try and keep a tradeoff between memory usage and performance. A smaller tightly packed data set will execute faster with CPU caches and will reduce page faults when loading and starting up.
6. Try debugging your code at the assembler level, stepping through it. It will help you better understand your compiler.
7. Don't bother trying to optimize things like getting every ounce of performance when the next function you call will be very slow. I.e. in one section of MS DOS's source code which was hand-coded assembly language it was calculating the cluster or sector of the disk to access. First the code checked if it was running on a 16-bit or 32-bit CPU. Next it took the 16-bit or 32-bit path for multiplication, then it read from the disk. Why the hell write all this code to check the CPU if it's 16 or 32 bit for the multiply when the frigging disk is going to be slow. They should have just stuck with the 16-bit multiply rather than be clever.
In general applications with GCC, I rarely see much difference between -O2 or -O3. For that matter, I often don't see a noticable difference between -O0 and -O3 for a lot of code.
I only see improvements in some very CPU intensive multimedia code. I also saw a significant improvement in some multimedia code when I told the compiler to generate code for an Ultrasparc rather than the default, but that's because the pre-ultrasparc code didn't use a multiply instruction.
-Aaron
This post is encrypted twice with ROT-13. Documenting or attempting to crack this encryption is illegal.
I wrote a chart control in C++ where I used bitshifting instead of multiply/divide and that is the only time (so far) where I was trying to squeeze maximum performance out of my app.
For the most part, unless you're writing anything with hard deadlines (RTOS', graphical stuff where visual matters, etc.) the time to look at the assembly is time wasted; better to get your algorithms right than to cut 10 instructions to two. Besides, most of the time, especially if you're doing "business"-related work, you're going to probably be bound by the disk or the network or other factors that makes the point moot.
So while good assembly is important, I'll trust the compiler does a good enough job for my purposes. However, that's not to say you can't help it along by passing by reference, using the STL properly, etc. Thus I try to strike a balance between readable/maintainable code, and performance. However, given that most of the things I write are business apps, maintenability will always always win out.
this is where C is different from most languages. C is more machine-like. The ! operator simply returns true if the variable being referenced is 0, and in terms of instructions, I believe this is actually a faster instruction, since most ALU's have an "is zero" line coming out of them.
A pointer is simply a number, in fact, really every variable in C is actually a number, including arrays that are really just pointers themselves that point to a continuous block of numbers.
Once beginners understand how generalC is, the rest is very easy.
Do not perform minor optimizations without first: a) Determining there is a performance problem b) Profiling your code to determine what areas should be optimized.
This does not mean that you should choose naive algortithms for the problem at hand. Choosing the proper algorithm for the problem at hand is always important.
Hand-optimized code should be reserved for those times when you have profiled your code with reasonable inputs and have shown that the lack of clarity is compensated for by the increased performance.
The example you gave is a perfect example of a hand optimization that is completely worthless with today's compilers.
I gave up doing atomic-level optimizations (loop and algorithm tightening is still OK) the day a buddy saw a compiler, when multiplying by 7, actually did a left shift of 3 followed by a subtraction, which were ALU rather than multiplication operations, and hence much faster.
(-1: Post disagrees with my already-settled worldview) is not a valid mod option.
I agree, as I have been recently poring through the code for PINE (the email program)... man, the code is very good about checking its pointers and function return codes, but they do it in the most obscure way, using the short-circuit evaluation features of the C language to its max -- as well as implicitly assuming that NULL == 0 == FALSE, which is bad in my opinion as the C standard never guarantees that NULL is actually 0 and FALSE is not a built-in data type.
.. while the code is correct, it's MUCH harder to parse.
I always find it harder to grok
if( !ptr || !func() )
return(0);
than
if( (ptr != NULL) )
{
if( func() == 0 )
return (0);
}
Many actual expressions in pine/send.c, for example, have as much as 6 terms in a single if statement which do a combination of NULL pointer checks, function calls, return codes and error returns.
ERROR 144 - REBOOT ?
For small scale code snippets (assigning a constant to a variable inside of a loop) the compiler knows to do that one time (outside of the loop) rather than the number of times the loop runs (you are assigning the variable the same constant over and over without doing anything otherwise useful). For larger scale operations where algorithms come into play, coding the algorithm wins (much bigger fish than mere optimization). Example: it's much faster to sort an array of data and do a binary search on it, than to leave it unsorted and do a brute force search on it (if you need to search the data more than one or two times). The search time (average hit time) for the unsorted search is 1/2 of the data. For a binary search, the seek time is ceiling(log(base 2)(data set size)). A million (unsorted records) takes on average 500,000 searches to find what you are looking for. If it's sorted, a binary search takes ceiling(log base 2(1000000)) or 20 searches. Another example of a divide-and-conquer algorithm is the finding of a very large exponent. Say you want to find the answer to 123456789.123456789 raised to the exponent 123456789.123456789... ..... ..... ... and solve for the decimal part of the exponent, that is the ...If the exponent is 2300 the whole process winds up looking like you are taking the product of base^2048 * base^128 * base^64 * base^32 * base^16 * base^8 * base^4. ...2048+128+64+32+16+8+4=2300 and you will have to keep track (count) how much you have accumulated. It looks like a lot more work and overhead, but it's wildly faster. /.ers really want to see how long 500 significant digits takes, just double-dog-dare me with a post). ...oh nevermind....
first you would split the exponent into a decimal/non-decimal number and use the rule a^(x+y) = a^x * a^y
then you would use the function a^b = e^(b * ln(a))
and e^x = 1 + x + (x^2/2!) + (x^3/3!) + (x^4/4!)
and ln(1+x) = x - (x^2/2) + (x^3/3) - (x^4/4) + (x^5/5)
123456789.123456789^0.1234565789 part of the problem.
The simplton (and silly) way of solving the whole number part of the exponent would be
to run a loop 123456789 times. But this would take a CRAY
several hours to crank out. Instead, the better way would be
to count the exponent in a better function base=base * base
where the first iteration is base=base *base
resulting in base ^2
the second time base=base*base
results in base ^4 (not base^3)
note that with a starting value of base^20, base =base * base
results in base^40
there is more overhead in counting how much 'exponent' you have accumulated, and how much you have left, but the speed is wildly faster log(base 2) of exponent. You also need to reset "base" when the next iteration will result in an exponent larger than what you want. If your exponent is 2300 and the starting value of base is 2048, the next iteration would be 4096 (which is way past 2300) so you would have to store away the result, and start again.
Oh, and by the way 123456789.123456789^123456789.123456789=
1.902372 233125202254900477527601440455865041458687 62E+998952458
and it took the comptuer
real 0m0.094s
user 0m0.062s
sys 0m0.005s
to finish it. That's an algorithm a compiler can't do (the result was actually done using an interpreted language, not a compiled one although if it was done with a compiled language it *would* be faster, and if
1.902372233125202254900477527601440 455865041584523 00932547800628012504668725985753569183588310325552 14891761772476982389287105899631335303898726939229 31310705257116814311279734672618273312947900668347 68090730923077415613982473794558850107588669012433 89234455684479444134741340809934899813201850775621 76899291838534784375714952525802050621884047640666 05875927322449991298143
Let's not forget how long it took them, either. I worked with some of the Shuttle programmers. I shared an office with one pudgy little 40-something bald guy who wrote about three lines of code per month. He had a big loose-leaf notebook full of all his test cases and his test jigs and his interfaces and his error checks. He worked for another guy who used to hold 1/2 day meetings every two days. In the time I shared a cubicle with him, probably 3 months, he had accomplished a whole lot of nothing.
As far as how together and structured the Shuttle group was, I remember the day there was a head crash on the 3330 drive that held all their source code. It was like turning over an ant nest, programmers scurrying around the halls screaming, etc. Don't believe everything those people write about how well they were organized and how wonderful everything was.
After more then 30th years of coding I have learned that if you want to "get it right" you must always get an assembly listing of the compiled code. This is the only way to verify that what was generated by the compiler is what you want the mechine to execute. Not only does this result in faster and/or smaller code, but also in zero defect code.
C++ still requires some undestanding of hand optimizations specific to the language.
//do something with class.
I don't think compilers optimize this construct.
for(;;)
{
MatrixClass C(3,3);
}
The C++ compiler will call the constructor/destructor every loop when it probably isn't needed. C++ and the "hidden" memory allocation, constructor, destructor calls can be a problem without arranging the code properly by hand.
That's the way. Write code that doesn't need comments to be understood, then comment the damn thing anyway ;-)
/why/ this routine does this this way, etc. Those are usually things you can't impart through the code its self anywhere near as easily.
There's very little more helpful than comments scattered through the code explaining the "bigger picture" -
Sometimes it's not the compiler doing the optimization. On an 8086, division was slow. /2 was a lot slower than >>1. It was possible to write a division function with shifts and subtracts that was faster than the DIV instruction. But now, the division function within Pentiums is optimized so that /2 is just as fast as >>1.
Intellectual Property is a monopolistic, selfish, and defective concept. It is "tyranny over the mind of man"
bestiality = cruelty to animals (mental, if not necessarily physical) = not the kind of thing I want happening.
feel free to fuck any consenting adult you want, however you want. don't molest animals.
'if (!ptr)' instead of 'if (ptr==NULL)'.
I only know a few high level programming languages (PHP, VBScript, and a few other misc languages), but it was my belief that with most programming languages, something can't be equal to nothing.
I have no idea what language the above code snippet is supposed to be, but I read the first code snippet as "if ptr is false". The second example jsut looks plain illogical to me.
What programming language supports that second code snippet? C/C++?
Isn't it good practice to keep "NULL", "false", and "0" seperate, since they are distictly different concepts?
I don't always use unix-like operating systems; but when I do, I prefer FreeBSD.
I must say I don't agree with the author's remarks on readability. I use
;)
if ( !ptr )
throughout my code for ages and always felt that to be far more readable, and so do my colleagues. It's also faster to type.
It reads "if no pointer" which is far understandable than "if pointer is null". Because pointers aren't really null, they are zero.
Mostly, it's just a matter of style. Imho, if you have trouble reading either of these though, you're using the wrong language - for your own safety stay away from Perl aswell.
"I don't mind God, it's his fan club I can't stand!" E8
I shared an office with one pudgy little 40-something bald guy
Who you calling pudgy?
Slashdot is full of pudgy little guys who are working hard on becoming 40-something and bald.
Though I'd hope to do something about the pudgy bit by the time I turn 40, my track record ain't so good.
I have found that over the years, very few problems require complex algorithms that have not already been coded. Knowing a library (STL, etc) very well and the language that implements it has almost always trumped knowing how to implement mergesort. If you think differently, go code up quicksort and then look at the std implementation....whoops, you are not as smart as you thought...the std library uses all sorts of language tweaks to blow the doors off of yours.
"I ask the Slashdot crowd, what they believe the compiler can be trusted to optimize and what must be hand optimized? Give examples of code optimizations that you think the compiler can/can't be trusted to do."
/.
Somehow 99% of the readers took this to mean "What is the difference between NULL and the zero bit pattern and do you think it is a good idea to write clear code and do the profile/algorithm change cycle until there is nothing left to optimize or should I write low level optimized code from the start?"
sigh.. I've only found two comments with code so far after going through hundreds of posts. This is possibly the worst signal to noise ratio I've witnessed on
C is definitely not going to be the language of the future. There are a lot of tools for "checking" or "purifying" C code, but real promise is in radical new approaches based on reusable objects. As far as a systems programming language goes, the Cyclone project at Bell Labs http://www.research.att.com/projects/cyclone/ is one way to get away from C.
The example given is down right stupid!!!
Who cares if it takes an extra usec to process ptr != NULL. How irrelevant. It won't change the efficiency of the program at all!!
This is what bugs me about "the C culture".. always concerned about micro efficiency. It is what stopped the C and C++ crowd from ever getting to real questions of over all design and efficiency (which are more often the cause of project failure).
Projects fail because the data requires moving/transformation, because you do more drawing than necesary, because you use bad algorithms and can't change them because you didn't design for that, because code is messy. None of these things can be solved by a compiler.
what the fuck handheld device has only 384k of RAM?
This the fuck handheld device has only 384k of RAM.
Well... I think Einstein had it right all along...
... My head hurts.
"Things should be made as simple as possible - no simpler."
- Albert Einstein
-ballpark
As far as I'm concerned compilers are better than 99% of the programmers out there. Just write clear code and let the compiler do it's trick. However there are a couple cases where things aren't automatically optimized that I can think of.
;)
.587h, .0114h)); I'm not sure if that bug still exists in the current compiler release or not.
/. posters just aren't aware of the short commings of compilers (see first sentence of this post) and would rather post obvious advice than not post at all. :)
It's not really a coding trick like an XOR swap, but most compilers don't yet seem to fully unroll parallel loops into good SIMD instructions or multiple threads.
The only time I've needed to bother to look at assembly output in recent years (other than debugging a release mode program) is when writing HLSL shaders. HLSL is the high level shading languge (C like) for shaders that is part of Direct3D 9. HLSL can be compiled to SM1, SM2, or SM3 assembly.
With pixel shader 2.0 you've only got 64 instruction slots, and some important instructions like POW (power), NRM (normalize), and LRP (interpolate) take multiple slots. 64 slots is not enough for a modern shader. I curse ATI for setting it bar so low.
There are two flaws I've found with the Dec 04 HLSL compiler in the DirectX. Sometimes it will not automatically detect a dot product opportunity. I had some colour code to convert to black and white in a shader and wrote it as y = colour.r*0.299 + colour.g*0.587 + colour.b*0.114; as I thought that was the most clear way to write it. Under certain circumstances the compiler didn't want to convert to a single dot instruction so I had to write as y = dot( colour.rgb, half3(.299h,
Another is often a value in the range of -1 to +1 is passed in as a colour, which means it must be packed into 0-1 range. To get it back you've got to double it and add 1.
a = p*2+1; gets converted into a single MAD instruction which takes one slot.
a = (p-0.5)*2; gets converted into an ADD and then a MUL.
Also conventional wisdom says you've got to write assembly to get maximum performance out of pixel shader 1.1 as it is basically just eight instruction slots. I don't have any snippets to verify this though.
I think this thread demonstrates that either compilers are mature enough you don't need any code tricks to help them do their job or
Quicksort has a worst case run time of N^2. A largish list can occasionally take *days* to compute, even though the average time is a millisecond.
Heapsort or mergesort is what should be used in any critical service.
For the rare performance critical parts it is however worth the effort to try various constructions to get the best performance out of the code. The most problematic issue is to identify the hotspots in the code and figure out which variables that should be declared as 'register' and those that shouldn't. Ordering of statements are also important in order to match the various performance improvments the CPU can offer. One very good document on this is actually found at AMD.
One code construct that I am using that I found is very useful is to place the matching '{' and '}' in the same column in the code. This eases the effort trying to find where a block begins.
Example:
In my opinion this produces code that has an improved readability compared to the constructs placing the '{' on the same line as the if-statement where it is much easier to miss.If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
I don't use compilers anymore.. I did in college,
but being a web programmer I use only interpreters.. But I never stop thinking about optimizing my code, I don't trust the interpreter to make things faster..
What I do in PHP, for instance is
$a = &$b;
Which is a pointer assignment..
But for some strange reason, everyone says
this is slower than
$a = $b;
Which really doesn't make sense..
He knows enough to ruin the world and his own. Does he know enough to change himself and the world as well?
A topic that guarantees to get every programmer to post to slashpot.. what batter way to stir a programmer.. tell them compilers can do a better job...
Is this a homework question?
Look into Compiler Tiling. It's all about reordering loops into ways that are more cache friendly.
Compiler writers are smart people.
Hey, my phone has a 400 MHz processor.
Bruce
Bruce Perens.
if (!ptr) and if (ptr != NULL) are exactly the same thing. It's like asking "which is cheaper, six eggs or a half-dozen eggs?" Show me the compiler that generates different code for those two snippets.
In other words:
"I'm too stupid and lazy to learn something challenging but rewarding, and I'm prone to talking like an asshat."
For example, for one loop, a=i++ became the best thing, but for another one, writing the code such that I could do a=++i was better!
In another (8-bit) compiler, writing to word was more effiecent than reading from a word, even though the CPU contained the requred instructions for equal effiecency.
When there's no particular need for speed, I just write for clarity. If I know that a function will be called several times, I sometimes make several attempts to find out what becomes the best code.
But in the end, leaving C and using the best possible assembler-algorithm might be the only option, since that way, for carfylly crafted code, I've experienced 5-10 times speed improvements, compared to the best possible algorithm in C.
For some unexplained reason VBScript evaluates the expression "" = Empty to True, but IsEmpty("") to False.
The issue has been discussed here
when I worked for a computer graphics company. What we sold was a routine for very fast voxel rendering. Our bottom line depended on the speed of the voxel rendering inner loop, and we beat the shit out of it. I wrote the reasonably clear, comprehensible version; then I spent a day with an optimization expert called Roger (Sayle, of Rasmol fame), who would send me off to get printouts of the assembly we generated and re-wire the code based on that, as well as on benchmarks of course. The code ran about 50% faster - a vitally important saving - but it took me another half a day to explain to the rest of the team how the code worked after it had been thoroughly Rogered.
Xenu loves you!
"ask slashdot"
I favor the "if(!bob)" style because I find it more readable.
If it's 99% true, then perhaps more than 80% of programmers shouldn't be writing in C. (Judging from the posts on this discussion I think I'm right ;) ).
:).
Because IMO nowadays writing in C is usually a premature optimization.
With all the GHz CPUs, higher level languages are often more than fast enough. It's usually the design and algorithms that you have to get right.
The advantage of writing in a higher level language first is you write far fewer lines of code - esp if the Customers keep changing their minds every month.
Optimizing at low levels only gives you linear improvements in speed. Doesn't help you if the system slows exponentially.
What I mean by linear is:
Say you use the same algorithm.
#1: fast low level language, optimized.
#2: in a fast low level language.
#3: high level language.
If #3 is 4 times slower than #1 in most cases it'll always be 4 times slower. Same if #2 is 10% times slower than #1.
Whereas a high level optimization can gain you lots more.
On a fair size complex system it's probably best to write stuff/modules in a high level language first and then replace them with C or hand assembly later if necessary.
Maybe it is wasteful. But at least you can say to the people doing it - the informal spec is: "it's got to work exactly like what you are replacing - only faster". After all that module is already working
Call the stuff in the high level language your pseudocode. The equivalent of the plastic/clay model or prototype.
For most cases anyway.
There are so many disadvantages, and you only get linear improvements in speed.
Write in a higher level language if you can.
If some guru optimizes the interpreter or compiler you get a linear improvement in speed.
Same if hardware gets faster or improves (e.g. 2nd level cache now big enough to fit your entire program).
If one part is not fast enough, then rewrite that part in C or machine code.
Call the high level language your pseudocode for C if you want.
I do not understand what you mean by the "most casual observer"... Typically, casual observers of code are coders, so most code can be written to be obvious to them. That means that comments should be used in the rare cases where it is not possible or very difficult.
Believe it or not, eschewing comments because "oh, well, if you want to understand it just read the code" just pisses those of us off who have to come along and clean up your miserable excuse for a codebase... and it sure as hell doesn't prove how studly a programmer you are.
No, programmers should avoid comments for clearer code not because it takes 20 seconds to write them, but because it takes a lot more time to update commented/redundant code and it usually leads to inconsistent and incorrect documentation as the code evolves.
Comments are a form of redundancy to the code as well as testing, static typing, etc. Redundancy has its advantages but it is mostly disadvantageous as it makes changes difficult and in the case it is not automatically checked for consistency (documentation) it usually leads to the lack thereof.
That doesn't mean half your codebase should be comments, but it does mean that you should at least make a passing nod to demystifying your own attempts at cleverness. I have lots of better things to do than to spend all fucking day picking apart your rabbit's nest of code before I can make a change, add a feature or fix a bug.
That's why code should not be clever, it should be simple and as obvious as possible.
People that honestly believe that "if it's well written it doesn't NEED comments" should be strangled with their mousecord and hung in their cubicles as a warning to the rest.
A lot of code can be written as to not require comments for proper understanding. The best documentation of what the code does is the code itself:
Its always up-to-date
Its always completely consistent with the behavior of the program
Its not ambiguous
Early optimisation is the root of all evil!
When programming always try to make the code as explicit and readable as possible.
Only bother with code optimisations for the very few paths that are actually part of an identified bottleneck.
A better algorithm is almost always better than bitfucking with an optimiser.
what must be hand optimized?"
Most desktop applications don't need to be optimised.
Those that do follow the 80-20 rule. They get 80% of the benefit from optimising 20% of the code. Often the ratio is more extreme. Most of the code doesn't need to be optimised.
When optimising, you won't get much benefit from jerking around with changing "if (!ptr)" to "if (ptr==NULL)". What you need is a whole different approach to the problem. e.g. Searching a list with a for loop? Is the list large and searching more common than insertion? Then it would make sense to sort the list first and use a binary search.
In conclusion: stupid question, especially from a 10-year coder.
My Karma: ran over your Dogma
StrawberryFrog
Personally, I prefer the !p form; I find it is clearer to say "p is an invalid pointer" than saying "p is equal to the the NULL pointer".
It is interesting to talk about readability vs. optimization, but this example is way too simple to be interesting.
Attention: According to the C ISO standard, NULL is platform dependent. A programmer must not assume NULL=0 if he/she wants to be sure his/her code is portable.
if(pointer==NULL) may be different from (!pointer).
if(pointer==NULL) is the correct way to check if the pointer is null, and is the cleanest way to type it.
Utter nonsense.
The REPRESENTATION of NULL might be different from the REPRESENTATION of 0. However, 0 converted to a pointer (usually implicitly through what's called a pointer context), will result in a null pointer in every conforming implementation. The NULL macro is just a convenience that helps readability in some contexts.
As an example; I used to programme assembly language on the Amiga 500, a long time ago, with the Motorola 68000 processor. You would presume that doing 'clr a0' should be quicker than 'sub a0,a0', wouldn't you? But after getting hold of a book with the actual cycles an instuction uses, I found out that the previous was quicker. (I hope I remeber the example from '88 correctly...)
So, my advice is that you optimize you C code as C, not as if it were Assembly Language.
Why? There are platforms (maybe there were, not sure) where NULL is actually not the same as 0.
www.vanheusden.com - home of Multitail, HTTPing, CoffeeSaint, EntropyBroker, rsstail, bsod, listener, nagcon, nagi
I prefer to strip all the non-whitespace from my programs.
</div>
See: comp.lang.c FAQ.
NULL is defined to be (void *)0.
can be expaded to .
Since pointer is, well, a pointer, the compiler can tell implicitly that it needs to compare ptr with a pointer with 0 value, which is defined by the C standard to be NULL.
However, NULL can be represented physically as non-zero bits, but C programmers should never care -- NULL is defined as (void *)0, so comparisons with 0 in a pointer context are equivalent to comparisons with NULL (whatever the physical representation of NULL is).
Most of the optimization are local, which may or may not improve overall performance. Besides, CPUs have their own local optimization for run-time execution.
If you can find a better algorithm, it's better to replace the whole algorithm than tweaking little things. Eventually CPUs and compilers do better automated jobs with local optimization.
It is not worth spending time and effort tweaking little things unless small cycle time is important such as in real-time embedded systems. But conventional compilers with good enough embedded processors are enough for non-hard real-time.
So why not one wearing a fursuit?
I'll just give you the citation and let you work it out from there: http://www.eskimo.com/~scs/C-faq/s5.html, especially questions 5.3, 5.5, and 5.10.
The short version: at the level of the C code, NULL is 0 - it has to be. Now, at the assembly language level, the compiler may translate 0 used in a context where it's a pointer to some other value, but at the level of the C source code, it is 0, regardless of CPU. (if it isn't, you're not using C, just some language that mostly looks like C)
The biggest problem I run into are programmers who "know the compiler" so much that they make impossible to decypher all-in-one-if-statement code blobs.
Write the damn code in a clear and precise way. Compile and run it. If performance is an issue (which for the majority of s/w it is not), then profile the code and make sure you know where the problem is.
Then, and only then, should the programmer consider rewriting code for optimization. And even then, often it is the algorithm that needs to be fixed, not the fact that the compiler's optimization is missing something obvious. These compiler thingies tend to to be pretty decent these days.
One of my favourite quotes I share with new grads as they come on-board with their fancy compiler theory classes under belt:
Given a pointer to an object, it is not the pointer which is null. The pointer is zero, it is the object which is null, seeing as it is impossible to obtain its value from a pointer with value zero. We just do the trick of using both pointer and its contents to represent incomplete information.
:)
:=)
;)
The concept of NULL is an extension to the domain of a variable. It means "no value". In C/C++, we often think of the pointer as the object itself, and as such we do the little trick of using two different operations to get that valuable extension to the domain: we either read the value of the pointer (a memory address) and compare it to zero or we load its content ( the -> operator ). However, why doesn't one usually compare pointers to static values other than zero( eg, ptr != 3 )? In not doing it, we bring to light the fact that we're just using part of the domain of the pointer variable.
To make this clear, think of what you'd have to do to have a null integer. In C you'd likely do:
int * val = malloc( sizeof(int) );
And then you'd use "val" for the null comparison and "*val" for the integer. Funny how in doing that you're spending more memory than if you did:
typedef struct { int value; bool isnull; } NullableInt;
NullableInt a;
With this you'd spend 5 bytes per variable. With the other approach you spend 4 bytes per variable plus 4 bytes for the pointer, for a total of 8 bytes (on 32 bit architectures).
Obviously, these considerations are a bit pointless, and one benefits little from them in the context of C/C++ programming.
On the other hand, some languages have specific support for nullable variables, without having to resort to pointers (at least syntactically). NULLs are famous in SQL, although they are also infamous for being used incorrectly many of the times.
"I don't mind God, it's his fan club I can't stand!" E8
From the FAQ you linked to:
[...] the preprocessor macro NULL is #defined (by or ) with the value 0, possibly cast to (void *)
You're still right about !ptr being equal to ptr != 0 or ptr != NULL, of course.
we are doing a development work (though i am not a programmer but more of a consultant.) i am emphasizing more on better code quality. it is easier to add new equipment to handle the increase load from more operations such as checks rather than modifying software that may potentially cause problems. it is easier to add new equipment than having to redo most of the code due to poor planning. it is easier to add new equipment due to increased load from designing your software to be very compatible to changes and customizations.
:) john
for me, programming is much difficult as it involves too much variables compared to hardware.
Live your life each day as if it was your last.
I go by the First Rule of Optimization: "Don't Do It" (occasionally, I will follow the Second Rule of Optimization: "Don't Do It Yet"). Two reasons:
1) Hand-optimized code tends to be harder to write, debug, understand, and maintain.
2) The compiler frequently does a better job anyway. Try comparing the standard strcpy function (while (*s != 0) *t++ = *s++;) with one that uses array indexing (while (s[i] != 0) { t[i] = s[i]; i++; }) using gcc -O3. On some versions and CPUs, the array-indexing code will actually use fewer instructions because the compiler gets more chances for optimization when you tell it that you're working with arrays. Pointer manipulation is for stupid compilers.
Of course, compilers cannot save you from bad design. Make sure to think about your O() factors.
-Lars
I'm guessing they won't be disappointed.
One word: Itanium.
My understanding is the the words snafu and foobar (orginally fubar) are acronyms, generated by soldiers during WW-II trying to assert their sanity and individuality within the impersonal bureacracy that is the military.
Snafu and fubar along with BUFF (the official military designation of the B-52 Stratofortress bomber aircraft) make use of a certain word. Since I am a civilian, I will use the civilian transliteration of the "f" as "fouled", although real military people don't use the civilian transliteration.
Snafu means "situation normal, all fouled up" and fubar means "fouled-up beyond all repair", while BUFF (a Vietnam-war neologism -- no one called it that in its Cold War role) means "big, ugly, fat, fellow" (OK, a variant on the f-usage.) From my aesthetics of things aviation, the B-52 is large, yes, but I think it is a rather sleek looking aircraft. The "ugly fat fellow" probably refered to the perspective of the enemy at the receiving end of the bomb pattern.
I had heard of fubar coming to computer usage when the run-time error message on some early FORTRAN systems for divide-by-zero was FUBAR -- the person writing the error message thought that was witty and probably didn't have any supervisor telling them to "clean that up" and "use something more explanatory and professional", and the geek FORTRAN programmers of that day were clean-shaven innocents with pocket pencil protectors who didn't know what fubar means.
The worst of this is Java example programs with
FooBar foobar = new FooBar();
My eyes glaze over when I see nonsense variables, especially in what is meant to be an illustrative example. The variable names can be short, but they should mean something, and is it possible to use Java examples where the class name and the object variable name are differentiated by more than change in case? Could we do
SampleClass sample_class_inst = new SampleClass()
fine by me (I'm a different A.C.). just NOT animals.
Thats funny, your girlfriend blows goats too
This sig is false.
Programmers deal in logic. Logic has an undeniable complexity. You can only simplify and describe behaviours in certain ways. If you try and re-write it in a way that doesn't reflect the true nature of the system you will certianly introduce bugs later on.
I believe most systems are programmable in one way, the core system, when you add frills and ui, it explodes into possibilities, but the logic of the system, at key points, it tied to your plan.
if you plan says that if Y == A, then X *must* == B, then there is a finite way you can code this.
Compilers on the other hand have to write the best code fo rhtis, again if the compiler is too clever then the window for compiler bugs increases.
So you shouldn't obfuscate a program to streamline it, as you will no doubt end up loosing this performance later on when you have to work around your constrictive programming.
practical advice?
Code predictively, do what the compiler expects. Very eay to do in Java. and of course, always let the compiler optimise.
Any optimisation of our 'program code' may well actually not translate into optmized object code... as high level languages might allow us to make 'optomized' code lines, but they translate into leg work at lower levels, leg work that reflects the convienience of the higher level of abtraction in your 'optimized code'.
mmm
#hostfile 0.0.0.0 primidi.com 0.0.0.0 www.primidi.com 0.0.0.0 radio.weblogs.com
C++ doesn't have implicit conversions from int to pointer (or pointer-to-member-function) types either, however a null pointer constant (which is an integral constant expression evaluating to 0) can be converted to either precisely because of a special rule, which could just as easily apply to (void*)0 as well, making C++ match C in this one case.
This is for anyone who still does not understand C's unary negation operators. Lesson #1: C has three different unary negation operators: logical (!), bitwise (~) and arithmetic (-).
p.s. C's predication expressions are always logically equivalent to !!x; therefore, you can unambiguously say "if (x)" and the compiler knows you're saying "if (x != 0)". Likewise, the same is true for "while(x)", "for(;x;)" and "(x) ? (a) : (b)". Similarly, you can say "if (!x)", and the compiler knows you're saying "if (x == 0)". People who do not understand C's unary logical negation expressions often mistakenly assume they have to use a binary equivalence relation instead. The submitter appears to have this confusion.
Um I hate to break this to you but CS people know the real meanings of snafu/fubar and choose to use snafoo/foobar because they're funny (to us).
If you're going to deal with CS types, you're going to have to accept that 'foo' and 'bar' are the two of the most popular temporary/example variable names around. Send any CS major to a whiteboard and ask him/her to use three variables. If you do not specify the purpose of these variables, you will probably get at least foo and bar. Some will mix in stuff like 'bleh', 'blah', 'duh' or 'doh' (though the squares among us often use a,b,c, i,j,k, or x,y,z).
Use of these variable names almost invariably signifies either (a) code example, (b) confusion/disagreement over requirements or (c) that the code is not production ready.
bool nothanks;
//it doesn't belong to Hank! (Not Hank's)
//They didn't want any (No Thanks)
//do you mean:
if(nothanks){
}
//or do you mean:
if(nothanks){
}
Please break your identifiers apart with underscores or mixed case!
I think using a bare bones language as plain C already comes pretty close to manual optimising.
In general, for each manual optimisation, a case must be based, preferably based on profiling.
Optimisation in its own is not bad. The problem is that it is too often done based on perception, and that perception is often down right faulty, or grossly out of date.
Use an inline function and let the compiler do the work...
...;
inline bool isNull(void *x) { return x == 0; }
if (isNull(ptr)) {
}
--
Roger
A LOT of embedded compilers are a LOT dumber than this.
Big chunks of metaware (a MIPS compiler), for example, appear to be based upon gcc version one.
Well, since I know .NET and I have used this ability in .NET I can speak to .net.
.NET has an easy way to do this.
Excuse me for trying not to be an expert on everything oh 'god of compilers'. If I had made a mistake on speaking to something else, you guys would be chewing out for a mistake. Now you're chewing me out for being too specific.
It is a fact that
A better way is:
Not all C/C++ compilers have Lint-like features, especially not those used for embedded software. Putting the constant first will transform those nasty unintended assignemnents into syntax errors.My opinion? See above.
void (*ptr)(void); /* .... */ /* ... */
...
if (ptr == NULL)
*** cc: error: incompatible types, aborting
So there probably is a good reason to use "if (!ptr)" after all, especially if you don't know C quite as well as you think you do. Cliches are cliches for some very good reasons
a) The Compiler actually doesn't infer the correct type most of the time but usually takes the literal and type converts it. Usually at compile time, but not always.
//prints infinity.
b) Nowhere did you say
float var = 0.0f;
System.println(var);
Since if that were true, then how in the world would he code you posted work? Was it a bug in the way that the PrintStream wrote the float? That might to have been the problem.
How did you know that the value of your float was exactly 0.0f (that number is representable in IEEE floating point)?
Compiler cannot reorder or do other optimizations with floating point code without potentially breaking something.
If this compiles, then the first thing you do is look at the compiler documentation, and choose a combination of compiler flags that stops it from compiling. if (var = NULL) will produce a warning on any decent compiler unless some really exceedingly dumb programmer has switched that warning on, and any decent compiler can be convinced not to accept code that gives any warnings.
If you can't convince your compiler not to accept if (var = NULL) then it is time to look for a different compiler.
b) Nowhere did you say //prints infinity.
float var = 0.0f;
System.println(var);
Dude...
If you try to print a float who's value is exactly 0.0f, it would print "infinity" instead.
I knew it was exactly 0.0f because somewhere earlier in the program I set it to that. The bug was definitely in the Metrowerks runtime. The code I posted worked fine because if the var was 0.0f it would print "0", and if it wasn't, then the runtime worked fine. I'm going to stop replying to this pointless thread now.
Hm, a few thoughts:
/thousand/ time improvement. No kidding.
:-)
;>
1. As your normal style, choose both clear and "fast".
Any optimizer worth its salt will give you nice, fast assembly for if(pointer) and if(0 == pointer) and if(!pointer), and if(NULL == pointer), and... you get the idea. Choosing one of these over the other is something of a holy war, but I'd say that you should here, as in most cases, pick what's easiest to read and don't sweat the details. That will be the least of your performance woes. Compilers really do a nice job handling this sort of thing. Choosing between for and while on some (usually old) platforms can make a (minor) difference, but again, don't we have better things to do?
So, what should be avoided?
You can find a lot of guidelines for avoiding the construction of code that is slower than it needs to be from "go"-- for example, use pointers when you can, they tend to be "fast". You can also use array indices. Fine.
But avoid duplicating data, setting sentinel values, needlessly traversing and/or doing compares that are redundant on your data sets, etc.. Your compiler probably just won't have any way of helping you there.
Those are the kinds of performance-impacting things that are in the programmer's hands-- usually, just let the compiler sort out the opcodes, you have bigger problems.
Watch what your algorithms are doing, and watch how many passes through the same data they make.
2. Measure.
You can waste a lot of time fiddling with the wrong parts of your program. Always ask yourself "is the problem that my function is slow, or is the problem that it's for some reason being called a zillion times". If it's being called a zillion times, "does it need to be"? If it's slow "why"? I've wasted a lot of time by not doing this, and I've saved a lot of time by doing it.
3. Solve the Right Problem.
Coming back to topic [1], passing data around and doing type conversion is slow-- and the compiler can't help you with it. So if you have unintentionally (or intentionally) gotten into a situation when you need to do numeric comparisons on strings, try to find a way to make it all integer, or at least reduce the number of conversions. This doesn't usually happen in languages with reasonable typing systems, thankfully, but happens all the time in languages that do a great deal of implicit type or even data conversion (figuring out which ones and in what cases is left as an excercise to the reader-- this isn't usually bad, they save you development time by doing this (well, okay, maybe not as much as we sometimes think...)).
The bottom line is that you should be using appropriate types and data for the operations you are performing.
(Note: Good use of parameterized types (some languages use "templates" for this) can help with this problem... a lot.)
How much of a difference can this make, and why am I spending so much time on it? Well again, without getting into specifics, on a recent project I improved a function's performance by about 500 times simply by rewriting it in another language. But then I had a mini-epiphany, and changed the way it worked so that the data and types agreed more closely... this was about a 35
While few results are (hopefully) likely to be so dramatic, the principle is a good one to bear in mind, I think.
3.5. "Premature Optimization is the Root of All Evil".
See [2] "measure".
(P.S.-- the guy to whom that quote is attributed knows a thing or two about the subject at hand.)
4. If the compiler can't do better than you can, it's time to optimize.
There are some cases where you can write better assembly code than the compiler. If you know when those are, you probably didn't need to read this though, did you?
It's said in real estate the three most important things are Location, Location, Location. Well, it seems, it's true in optimization too.
On second thought, the three most important things in optimization are Measure, Measure, Measure. You need to measure before you can optimize. If you don't measure, you don't know what really needs to be optimized. You have to profile to properly optimize.
Anything else wastes valuable time. Unless you optimize the parts that are executed the most or which slow down the process the worst, you are "very efficiently wasting time."
The lessons of history teach us - if they teach us anything - that nobody learns the lessons that history teaches us.
What programmers should mainly worry about today is speed and size complexity, not some cheap tricks IMHO. Of course, it depends on the compiler. If it is a promptly hacked together embedded C compiler with no optimization options, you might wish to be much, much more careful about what you are doing. Otherwise, happily use whatever you need, and let the compiler worry about the tiny details.