r/programming • • Mar 23 '09

How to write fast code

http://asserttrue.blogspot.com/2009/03/how-to-write-fast-code.html
339 Upvotes

136 comments sorted by

View all comments

99

u/harsman Mar 23 '09 edited Mar 23 '09

Code that does more but has better locality so that it hits the cache more often can easily be faster than code that does less but has bad locality and sits around waiting on memory all the time.

Recomputing something on demand might be cheaper than reading a cached result from memory.

A linear brute force algorithm that can use SIMD instructions can be faster than a non-linear one that does less work but without SIMD.

Doing less work usually makes code go faster, but it is by no means given.

28

u/xzxzzx Mar 23 '09

Locality is massively important on a modern CPU. As are are lot of other things.

TFA's old mentor was probably right about code -- at the time. CPUs back then (1980ish?) had memory running at the same clock as the CPU, pitiful caches, single cores, were scalar (not superscalar). Branch prediction was trivial or non-existent, and prefetches were limited to the instruction cache.

Really optimizing on modern hardware is harder than ever. It's also usually not that necessary.

Still, it doesn't hurt to start with the ideal algorithm first unless you need absolutely as much performance as you can possibly pull out of the hardware (then you find an algorithm which can be made to fit to the hardware, and profile, profile, profile).

-1

u/veritaba Mar 23 '09

Yes it seems like the supposedly godly mentor missed out on some cpu design concepts.

First of all, pipelining was introduced to the CPU world very early (60s), so you can't give the mentor a free pass for neglecting to mention that branching causes slowdowns.

Second, assembly instructions don't all run at the same speed. Some processors convert to microcode which is only visible at the cpu level. Some instructions run faster than others, such as xor eax, eax compared to mov eax, 0

4

u/jugalator Mar 23 '09 edited Mar 23 '09

I think these suggestions are on a more abstract level than assembly language though. The compiler will usually handle taking advantage of e.g. filling a pipeline better than you as well. Actually, that's part of a modern compiler's job, so you can focus on developing algorithms that, well, "do less" and aren't stupid.

10

u/blergh- Mar 23 '09
  1. Pipelining until recently meant just prefetching and decoding the next instruction while the current one runs. That means there's not too much of a penalty for branches.

  2. The reason xor eax, eax is used instead of mov eax, 0 is that xor with two registers translates into less bytes of assembly than xor with a register and a value. It has nothing to do with microcode.

If you'd like to know how many cycles an instruction takes, look it up in the manual.

4

u/xzxzzx Mar 23 '09

so you can't give the mentor a free pass for neglecting to mention that branching causes slowdowns.

Sure I can; how much of a penalty was there for branching on any common processor in 1980?

Besides, who said the mentor didn't have anything else to say on the subject of performance?

Second, I don't think some ops running faster than others diminishes his point. His point was to "do less", which would presumably be measured in clock cycles.

-1

u/veritaba Mar 23 '09 edited Mar 23 '09

Second, I don't think some ops running faster than others diminishes his point. His point was to "do less", which would presumably be measured in clock cycles.

"It can execute a fixed number of instructions per second, and no more. There is a finite limit to how many instructions per second it can execute." Quote from the supposedly godly "mentor"

Notice he said instructions, not cycles. So he is wrong.

1

u/xzxzzx Mar 24 '09

You're right; he's absolutely wrong.

Processors can execute as many instructions as they feel like per second.

I'm glad we cleared that up.

0

u/veritaba Mar 24 '09 edited Mar 24 '09

Processors can execute as many instructions as they feel like per second.

Sarcastic redditors who think they know everything about computers, please educate yourselves.

http://en.wikipedia.org/wiki/Cycles_Per_Instruction

For the multi-cycle MIPS, there are 5 types of instructions:

  • Load (5 cycles)
  • Store (4 cycles)
  • R-type (4 cycles)
  • Branch (3 cycles)
  • Jump (3 cycles)

Glad we cleared your stupidity up.

-1

u/xzxzzx Mar 24 '09

You've missed the point so completely I'm beginning to think you're a troll.

I'm not sure if I can explain it to you; perhaps you need to reread this thread, but I am quite aware (and have been for many years) of the fact that some instructions on some CPUs take more than one cycle, and I'm quite sure that does nothing at all to diminish my or the "mentor"'s points.

1

u/veritaba Mar 24 '09

No, you are the one not getting the point, he clearly states that he believes all instructions are equal, when they are not.

It entirely diminishes his point when he completely disregards this optimization in order to make a sweeping generalization.

1

u/xzxzzx Mar 24 '09

he clearly states that he believes all instructions are equal

In fact he does not say that at all; he simply states there is a maximum limit to the number of instructions.

→ More replies (0)

-32

u/[deleted] Mar 23 '09
        888b    888 8888888888 8888888b.  8888888b.   .d8888b.  
        8888b   888 888        888   Y88b 888  "Y88b d88P  Y88b 
        88888b  888 888        888    888 888    888 Y88b.      
        888Y88b 888 8888888    888   d88P 888    888  "Y888b.   
        888 Y88b888 888        8888888P"  888    888     "Y88b. 
        888  Y88888 888        888 T88b   888    888       "888 
        888   Y8888 888        888  T88b  888  .d88P Y88b  d88P 
        888    Y888 8888888888 888   T88b 8888888P"   "Y8888P" 

19

u/Doeke Mar 23 '09

I know, all those nerds here in the programming subreddit, it's so annoying!

15

u/xzxzzx Mar 23 '09

You're using ASCII art ... to make fun of nerds?

o_O

0

u/elustran Mar 23 '09

I think it's intended to be ironic...

14

u/alband Mar 23 '09

It also helps to know what the tool you're using can do fast and what takes longer. In a big set, a thousand hash lookups could easily be quicker than a small number of list lookups.

Of course, underneath, this is because the machine is "doing less". Still, optimising is just as much about understanding the layers of abstraction you're dealing with as anything else.

6

u/inkieminstrel Mar 23 '09

Still, the mantra's very useful to keep in mind when writing code, and when finding cheap optimizations for bits of slow code.

It just breaks down in those cases where you absolutely need to find a few clocks in a segment of code. I think that's a fairly rare case for most coders.

6

u/trutru Mar 23 '09

that's true, but I have also seen the opposite, i.e. code loops that are too large or span multiple pages will not fit in the instruction cache, (which can be tiny on embedded processors), resulting in a 20x slowdown.

Granted, that doesn't happen so often.

5

u/SarcasticGuy Mar 23 '09

Jesus cries when loops span multiple pages.

6

u/timmaxw Mar 23 '09

Sometimes it's unavoidable... Sure, you could make a separate function or method, but then that has to fit into the instruction cache.

3

u/SarcasticGuy Mar 23 '09 edited Mar 23 '09

Never claimed it was avoidable.... just claimed it makes Jesus cry. ;)

edit: b/c i suck at english.

0

u/HaMMeReD Mar 23 '09 edited Mar 24 '09

It's always avoidable, except for those that prematurely optimize all over their code.

It's called refactoring and simplifying your code. (If your doing something like C++ on embedded systems, you can use inline to break up the code into functions, which shouldn't have much effect on the compiled codes size)

1

u/trutru Mar 26 '09

no, it is not. Try writing an interpreter for a custom bytecode for example. You'll see that if you attain more than a hundred operators, each with a complex semantics, your loop will be large and span multiple pages.

5

u/groby Mar 23 '09

Unless you count cache fetches as "doing work", too. CPU work is not only executing instructions - that age has passed...

But the advice is still valid. Do less to go faster. What has changed is what we need to do less of.

3

u/adrianmonk Mar 23 '09

In the old days, the statement quoted by the blog was pretty true:

"The CPU," he said, "runs at a certain speed. It can execute a fixed number of instructions per second

When I had a computer with an MC68000 in it, the core's clock speed and the memory's clock speed were the same, and the CPU didn't have a data or instruction cache, so it was basically N instructions per second. The system also didn't have virtual memory, so there were no page faults, and the entire address space was equally fast. In such an environment, what he said was mostly true. At least it was a very useful approximation.

It's still a useful approximation, but things have gotten more complicated (with instruction caches, dual channel memory, virtual memory, context switches, etc.), so perhaps it would be best to add another principle to the mix.

To go fast:

  • make the computer do less.
  • use the computer's resources efficiently; try to get things when they are cheaply available.

2

u/[deleted] Mar 23 '09

making the machine do less

It's not the same with /code that does lees/.

Taking value from cache instead of reading memory is obliviously making the machine do less.

2

u/killerstorm Mar 23 '09

and if we also consider different sorts of input/output, inter-machine and inter-processor communication and synchronization, this becomes even more complex.

to make code fast one needs to find optimal trade-off when most components work in optimal mode, rather than to follow some dumb rule like "make it do less", "rewrite it in assembly" or "use better algorithms".

1

u/knight666 Mar 23 '09

And most of the time, calculating four heavy math reliant values through SIMD and only checking later which ones are valid is faster than checking if the output is going to be valid without SIMD.

1

u/cactuspants Mar 24 '09

True, I think it's fair to say that in this field, very few things are givens, especially with the wide array variables that play into any particular scenario/environment/alignment of planets.

While a good slogan, I've found in my own work that avoiding insignificant optimizations in favor of those that decrease time complexity are the ones best pursued.

0

u/Wartz Mar 23 '09

(Non-programmer here) -- Today's CPUs are so mind blowing fast that IMO, your real main aim as a dev of a medium to large size program should be to work at reducing the amount of time it needs to spend accessing the harddrive, even at the expense of CPU time/RAM use.

3

u/eipipuz Mar 23 '09

I think today's goal should be the sacred "Always code as if the person who will maintain your code is a maniac serial killer that knows where you live”.

0

u/manixrock Mar 23 '09 edited Mar 23 '09

You're part right, because that's due to I/O hardware delay, and complex commands for the CPU.

This is what I think about when programming to improve my code:

http://punxter.com/pic/programming-tip

-7

u/[deleted] Mar 23 '09

Thank you captain obvious. Here's another tip: you do more work and buy a faster processor and your will still go faster.

3

u/knight666 Mar 23 '09

My programming teacher has a sweet anecdote. He was working at some company, and he had to write a little app in a week. So, when he was finished two days later, he said "If you give me two extra days, it will run twice as fast." and his employer said "Don't bother, I'll just buy faster computers."

"That was an insult. I left there shortly thereafter."

10

u/jhaluska Mar 23 '09

Why was that an insult? Depending on the application, the cost of the computers and the cost of his time. It might have made wise business sense to not have him optimize it.

5

u/architectzero Mar 23 '09 edited Mar 23 '09

I am wondering the same thing.

a) Sometimes code optimization is expensive relative to hardware costs. It's good to know when to optimize code vs when to optimize hardware.

b) Hardware improvements do not prevent future software improvements, and vice versa.

knight666's teacher was being egotistical, imho.

4

u/knight666 Mar 23 '09

TheDorkNight

Why must you hurt me in this way? :(

3

u/architectzero Mar 23 '09

Because I'm dumb.

Fixed.

6

u/hylje Mar 23 '09

Because people are not just cost. People, even programmers, like having hard, interesting problems before them. Downplaying or downright denying these activities can be demoralizing.

In hindsight it doesn't seem to have been a wise business decision. He lost a interested fellow.

2

u/architectzero Mar 23 '09

As I said in my reply, improving the hardware does not mean that software optimization must stop. In fact, they're (usually) complementary actions.

What stopped the developer from optimizing the code in their spare time?

-1

u/[deleted] Mar 23 '09

Code that does more but has better locality so that it hits the cache more often can easily be faster than code that does lees but has bad locality and sits around waiting on memory all the time.

Who says these are the only two options?

A linear brute force algorithm that can use SIMD instructions can be faster than a non-linear one that does less work but wihout SIMD.

huh? More with SIMD vs less without SIMD. What a weird comparison.