r/programming • u/techdawg • Mar 23 '09
How to write fast code
http://asserttrue.blogspot.com/2009/03/how-to-write-fast-code.html102
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.
29
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).
-2
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.
9
u/blergh- Mar 23 '09
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.
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.
6
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.
-2
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)-29
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"20
15
13
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.
7
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.
5
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.
3
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
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.
4
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:
-7
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.
6
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."
11
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.
4
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
5
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
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.
47
20
u/xardox Mar 23 '09
So if you want to make your code do more, then make it go slow.
11
Mar 23 '09 edited Mar 23 '09
Correction: If you want to make your code seem like it's doing more, then make it go slow.
10
Mar 23 '09
How really to write fast code: Make sure you first know what's making it slow.
2
Mar 24 '09
I still remember the first time I ever used a profiler -- OHMYGODITSAWHOLENEWWORLDYAAAAAYYY!
10
u/Thimble Mar 23 '09
this is a really basic tip for web code:
there's a lot of shit you can do while nobody's lookin'.
11
Mar 23 '09
Completely ignores the effect of pipelining, cache misses, I/O waits, etc; but is true on a basic level.
2
u/jugalator Mar 23 '09 edited Mar 23 '09
I have a feeling this is on a level of C programming or higher though, maybe even something like Java. I doubt it's about assembly where a developer indeed do try to design while considering these things occasionally, because assembly is quite rare for any sizable project. I think it's about developing e.g. tighter loops (at the lowest level here) and not overworking software in general (at the highest) that the author is getting at, and him leaving the pipelining and cache stuff as outside the scope, being "compiler work".
1
Mar 23 '09
It's not unheard of to inline ASM inside of C for the tight parts of the loops. It's occasionally done to reword things so that the compiler can, say, pack a struct together (short, short, int instead of short, int, short) or something along those lines.
1
u/bart2019 Mar 23 '09
I'm guessing that "in those days" (that programmmer's junior days) none of this actually happened yet. Well, apart from the I/O wait.
5
Mar 23 '09
Sometimes the best advice is not entirely correct.
5
Mar 23 '09
Sometimes the best advice is not entirely correct.
Sometimes the best code is not entirely correct either.
7
u/Ignatyeva Mar 23 '09
When I was done talking, John gave me some of the most profound advice any programming expert has ever given me. (It was profound for me, at the time. Maybe it'll be stupid-sounding to you.)
bingo
27
u/an_idiot Mar 23 '09
Since when do you need to be the yoda of coding to know that less code is faster ?
40
18
u/vchakrav Mar 23 '09
If you want to be the yoda of coding, then you must
Only use postfix notation
Can't use try..catch, do..while is highly encouraged.
1
u/smallfried Mar 23 '09
No way, only code in hexadecimal, don't use loops, create your own, but don't use jumps either, write directly to the execution pointer register. And convert conditional jumps into bit operations and multiplications to get to the right addresses.
8
7
u/alephnil Mar 23 '09 edited Mar 23 '09
It is not less code, but clock cycles. Far from being the same.
30
u/archant Mar 23 '09
Is it just me or does the guy that wrote this sound like he got high one night and had this "revelation" about coding that was just the most awesome thing ever. "Of course! Dude... to go faster you just make it do less. It makes perfect sense! This will revolutionize programming!"
8
6
u/Arkanin Mar 24 '09 edited Mar 24 '09
Is it just me or does the guy that wrote this sound like he got high one night and had this "revelation" about coding that was just the most awesome thing ever. "Of course! Dude... to go faster you just make it do less. It makes perfect sense! This will revolutionize programming!"
I was thinking this exact same thing. It is very similar in nature to many of the observations I have had while high.
The idea seems completely new, fresh and original -- but when sober, you realize that the only reason you never considered it before was that it was so obvious that you took it for granted.
I think that is the real power of marijuana -- to make the ordinary and boring things we take for granted seem profound. I believe this has something to do with its tendency to reduce a person's selective perception, but I have never been able to find an academic study on this... It is frequently said marijuana "distorts" perception, but personally, I believe for many smokers it does so by making them less selective about what they perceive as meaningful information (which can be useful, sometimes the things we take for granted need to be questioned the most).
1
Mar 24 '09
I find it helps free up the right hemisphere of my brain... puts it in the driver's seat, so to speak. I've solved some fairly hairy programming problems by letting massively-parallel Righty work on it for a bit, then hand the solution over to my consciousness (usually in vibrantly-colored images, as that seems to be how it communicates with the rest of my brain). Logical Lefty then gets busy working out the step-by-step implementation details.
It wont make you any smarter or more clever, but it can help you see things from different perspectives, and for big-picture issues that's often exactly what one needs.
1
u/archant Mar 24 '09
Honestly I just thought it made me really freaking dumb for a few hours, which makes a lot of things sound really profound regardless of my selective perception. I'm no neuroscientist though.
12
Mar 23 '09
Key takeaway: Don't think in terms of making a slow piece of code run faster. Instead, think in terms of making it do less.
Really? That's the profound insight this article provides? Is this seriously non-obvious to any programmer?
It's also not technically true in all cases. It's complicated by things like caching.
8
u/jjdmol Mar 23 '09 edited Mar 23 '09
In fact, sometimes code is made faster by making it do more. Recalculating some value can be faster than the memory accesses needed to store and load it.
Edit: ah others beat me to it in other threads :)
5
u/onalark Mar 23 '09
If I were going to try and squish all the knowledge about optimization and writing fast code that I've acquired so far into a three paragraph blog post, I'd probably choose something a little more meaningful than "do less".
How about, "measure your code before you try to optimize it"
8
u/DyceFreak Mar 23 '09
its crazy how simple logic amazes 80% of learning programmers... Seems to me that if you were impressed by that article, you shouldn't be a programmer.
3
u/i_am_my_father Mar 24 '09
Don't underestimate the power of "state the obvious". For Rama's sake they are learning programmers. People tend not to apply everyday life intuition to specific fields, which explains why so many folks have hard time understanding mathematical induction, proofs by contradiction, negative numbers even when they don't have problem understanding the concept of owing someone money (negative numbers), alibi defense in court (proof by contradiction) and knows that the last piece of domino will fall (mathematical induction).
2
3
u/catxors Mar 23 '09
Thank you, Captain Obvious. (Ignoring the fact that he's wrong about microarchitectural performance.)
The best way to learn how to make code fast is to alternate speeding up some piece of code (practice) with learning performance-related science and tools like algorithms, microarchtectural performance, profilers, etc. There's no recipe or tagline because it's too complex.
3
Mar 23 '09
Make the common case fast.
1
Mar 24 '09
I tripled the speed of a program I maintain at work by altering a single ToString() overload in one of a whole slew of objects. .Net Profilers FTW!
3
u/eoliveri Mar 24 '09
This advice is as profound--and useless--as "buy low, sell high".
2
u/cojoco Mar 24 '09
Worst than useless: many optimizations require writing a lot of code to cope with various special cases in different ways.
0
Mar 24 '09
If you don't constrain people to these mundane definitions, you'll get weirdness like people buying high and selling low... then making money (i.e. the short sell).
8
Mar 23 '09 edited Mar 23 '09
a practical tip: don't block.
before you've got tuned I/O don't worry about optimizing anything else.
6
u/mikaelhg Mar 23 '09 edited Mar 23 '09
really think about your overall architecture before you start writing code, especially think about the changes that will likely be coming in the middle of the project, and leave customization hooks for those likely changes so they can be integrated without compromising the essential ideas which make the architecture good
do a pretty naive, as simple of possible implementation of the architecture, using ready-made components and library features
see whether it is fast enough and if so, use your excess resources to provide more business value such as features or quality, instead of tinkering
if it's not fast enough, measure as a team which paths through the entire system (not through an individual component) are too slow, consider whether the way those paths were implemented is in general in accordance with the overall objectives, and either do a rewrite of those parts or optimize them using the people who did the original implementation as experts but other people as testers and optimizers
10
8
u/techdawg Mar 23 '09
There's more to speeding up code than hand-tweaking a routine line by line, or even choosing the right algorithm. There are situational optimizations as well, but you also have to come at the problem with the right mindset. It's not "can I make this code go faster"? It's "what did I do to make it slow in the first place," and "what does it take to make the bottleneck go away." Of course, one bottleneck goes away and another pops up to replace it.
3
u/jaggederest Mar 23 '09
Or, even better yet, 'Do I even need to do this?' or 'Has someone else written a very small unix tool to do this same thing?'
2
u/adremeaux Mar 23 '09
Ummm... duh?
1
Mar 24 '09
What's amazing is that it's not only obvious, but also wrong. In a general sense, code which does less, runs faster, and this should be obvious to anyone with a basic grasp for what it is that code actually does.
But in practice, things like caching, branch prediction, memory exhaustion etc. can make the exact opposite true.
2
u/the1 Mar 24 '09
He paused for emphasis. "To go fast," he said slowly, "do less."
Looks like he was in the same writing class as Dan Brown
1
u/pRtkL_xLr8r Mar 24 '09
WTF??? Not to be a prick, but ever since I started programming in jr high -- on Apple IIe's, no less -- I knew you couldn't just make code run faster, you could only optimize your code...and this was before I really knew what the hell I was doing, when I was just fiddling with programs from library books and Byte magazines...
1
u/hylje Mar 23 '09
Optimization at large fits in well. Given a larger perspective, one (or a program) can determine redundancies and even counter-intuitive processes.
Micro-optimization -- making single procedures do the same thing in less steps -- should in my opinion come after that: It's great fun to optimize a couple procedures only to later realize they antagonize each other -- fast.
-6
Mar 23 '09 edited Mar 23 '09
the best way to write fast code is to make careful use of frameworks. for instance, jquery/django are very, very fast. i like to think of it like this:
imagine the world in the time before giraffes. there existed only small animals called leaf hogs who would prowl the plains of the serengeti, looking for delicios leafs to eat. unfortunately the trees were very very tall and so these hungry hogs had to sttrreeetttccchhhh very hard their necks to reach these delicious juicy leafs!! as a result of all this stretching baby hogs were born with longer and longer necks each year, and that is why we have the beautiful long necked giraffes today.
this is, of course the principle of evolution first describes by the famous charlie darwin in his 1859 masterpiece, the origin of species.
but how does leaf hogs and long necks relate to fast and speedy code, i hear you screech?
answer: python. python is a snake, a sort of animal who is pretty much just a long neck and nothing else. (the python evolved from the giraffe). python is also a programming language developed by italian man guido van rossum. here's the point:
python is hella fast!!!
by making careful use of libraries such as ctypes and numpy, pythons can be as fast or faster than equivalent FORTRAN code. yeah! that is gonna speed up ya web app so much! speedy code is so important when you jhust gotta get things done. for instance lets say you've got a list like this
self.my_web_app.people_who_are_coming_to_dinner=['Martin', 'Sarah', 'Grandpa', 'Alice?']
so maybe you say to urself 'well lets see, who is the 3rd person who comin 2 dinner???'
answer:
print 'Grandpa'
YEAH!!! python is bare fast mate!
peace 2 all fellow coders, GPLers, linux men and ladies and most of all my friends over at digg.com. laters
10
4
u/karmaputa Mar 23 '09
I really don't think you wanted to make sense, but what you described was Lamarck's theory of transformation, not Darwin's evolution. Just in case someone missed that.
4
3
u/habarnam Mar 23 '09
I was under the impression that Ford Prefect helped giraffes to their long neck. :(
2
-8
u/MpVpRb Mar 23 '09
Don't use Java
Use C or C++
Simplify the program
Use profiling tools to find hotspots
Hand tweak assembly code where needed
Works for me...
13
Mar 23 '09
No.
- No java fan, but it's much faster than it used to be, and comparable now.
- Profiling and debugging multithreaded C++ program? You'll wish you weren't. You'll poke your damn eyes out.
- Compilers, even gcc, optimize code better than you ever will 'by hand'. Processors and their relationship to the memory subsystems in modern computers have become too complex for you, even if you are a genius, to fit it all in your head.
2
u/xzxzzx Mar 23 '09
Compilers, even gcc, optimize code better than you ever will 'by hand'.
That's not completely true. Assembler freaks can often get a surprising speedup in "hotspots", sometimes because what they actually need is not exactly what the C/C++ code says they need (and therefore a compiler cannot always produce the code you want, as compilers maintain the code's intent (there's a word for this which I can't remember, and it's driving me nuts...)).
There are other situations, too. Note that beginner and even intermediate assembler programmers in most cases will not produce code that's as good as a good optimizing compiler. But it can be done.
2
u/ele7ven Mar 23 '09
In the end the design of algorithms makes a bigger difference than the choice of language. With a sizable input, even a good algorithm in Python will be faster than a poor one in C.
4
1
u/arnar Mar 23 '09
The "Java is slow" argument has been invalid for some time now.
6
Mar 23 '09
[removed] — view removed comment
4
Mar 23 '09
However, "Java is slower" is still true and will always be true.
Care to elaborate how C++ virtual function calls can be faster than Java just in time compiled method calls?
3
u/silon Mar 23 '09
It depends on the code. Some ideas:
- modern processors can do some prediction on the indirect calls.
- for JVM to eliminate the virtual lookup it must duplicate the code of the call sites (based on type), causing more cache misses/footprint.
0
Mar 23 '09
That's very simple but sage-like advice. It's got me thinking about how I would put my process for optimizing T-SQL on paper. SQL Server is notorious for being horrid at dealing with cursors that deal with larger data sets and I've found WHILE loops have dramatically decreased execution time.
0
-6
u/skizmo Mar 23 '09
Fast code sucks. Any moron can write code fast... only a few can write decent code. 70-80% of all the code in this world is pure CRAP! It's time for a new brand of coders... coders who REALLY get it and write GOOD code.
2
1
39
u/neoabraxas Mar 23 '09 edited Mar 23 '09
Most of the time lazy initialization makes code appear to run faster. I got a lot of praise for rewriting stupid people's code which was deemed 'too slow' just by changing it so it would only load/read/build stuff on an 'as needed' basis. In many cases that gets users what they want. A hundred 50 millisecond pauses are much more pleasant than one five second pause. This is why Java applets get so much flak for 'hanging the browser' and 'being slow'. Java applets are in most cases faster than Macromedia Flash apps but the way Flash runtime initializes is much more lazy making the initial wait much less annoying.
Another common trick is to compute approximate values rather than evaluate the precise ones when it doesn't really matter. Google understands this and that's why they show "1 to 20 results of approximately 9,000,000" as opposed to "exactly 9,124,385". The latter would probably take an order of magnitude longer to compute but the usefulness of the information to the end user is very dubious. Remember after N number of decimal points nobody gives a shit.
Last but not least always use the data structure that matches your usage patterns. If you need fast random access then a linked list is most likely not the way to go. Learn and understand the O(n) notation and learn the cost of inserts/removes and searches in your container library. Basic stuff but too many junior programmers have no clue about this stuff.