Optimizing: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
→‎Compiler Optimization: added note on how was errornous anyway, as per Solar's comment on talk page.
Rewrote first paragraph/introduction bit.
Line 1: Line 1:
Optimization is the practise of taking functioning code and modifying it in order to make it execute faster. Optimization is already discussed very thoroughly in other places for various userland problem domains, and below are a few areas that are important for operating system developers to consider.
Optimizing is a common thing in programming, but is also very important when you are programming an Operating System.

One of the important things about optimizing, is that you have to know where to optimize, and where not.
Note that to fully understand the ideas on this page, it is important to have fairly good grasp of assembly (x86 examples will be used), and a thorough knowledge of the x86 architecture is a must. But you've already read the Intel CPU manuals, haven't you?


==When and What to Optimize==
==When and What to Optimize==
Line 12: Line 13:


There is also some places where you don't need to optimize, because it would not help much. Generally, things that are not worth optimizing are things that only run once: loading an [[IDT]], enabling [[Paging|paging]], and crash recovery (emphasis in that case should be on stability, not speed).
There is also some places where you don't need to optimize, because it would not help much. Generally, things that are not worth optimizing are things that only run once: loading an [[IDT]], enabling [[Paging|paging]], and crash recovery (emphasis in that case should be on stability, not speed).

Note that it is useless to optimize code that isn't working, or hasn't been tested yet.


'''This is the first step, to fast code.''' What does this mean? [[User:Jackscott|Jackscott]] 10:38, 18 November 2008 (UTC)
'''This is the first step, to fast code.''' What does this mean? [[User:Jackscott|Jackscott]] 10:38, 18 November 2008 (UTC)

Revision as of 08:32, 20 November 2008

Optimization is the practise of taking functioning code and modifying it in order to make it execute faster. Optimization is already discussed very thoroughly in other places for various userland problem domains, and below are a few areas that are important for operating system developers to consider.

Note that to fully understand the ideas on this page, it is important to have fairly good grasp of assembly (x86 examples will be used), and a thorough knowledge of the x86 architecture is a must. But you've already read the Intel CPU manuals, haven't you?

When and What to Optimize

As said above, there is a time you have to optimize your code, and sometime it does not matter. There is one main place where optimizing is a very good idea: loops. Why you might ask yourself, because if you run though a loop 1 milion times, and there is just one "unnecessary line of code", then it matters a lot.

Loops are not the only places to optimize, places like:

  • Often run code
  • Graphics code
  • API code

and so on.

There is also some places where you don't need to optimize, because it would not help much. Generally, things that are not worth optimizing are things that only run once: loading an IDT, enabling paging, and crash recovery (emphasis in that case should be on stability, not speed).

Note that it is useless to optimize code that isn't working, or hasn't been tested yet.

This is the first step, to fast code. What does this mean? Jackscott 10:38, 18 November 2008 (UTC)

Compiler Optimization

If you're using one of the more complex compilers (such as GCC), you have available to you a lot of optimizations that can be done without having to write (or remove) a single line of code. One thing to be aware of when using compiler optimizations is that when overdone (or even done at all) they can cause previously functioning code to become buggy, or not work at all. It is important to remember that this is not so much a problem with the optimizations the compiler does, but the fact that the code had underlying errors in the first place. That is to say, not using the volatile keyword correctly.

To use compiler optimizations in GCC, simply add the -O(x) switch to the command line when compiling, where (x) is one of the following:

Switch Use
s Optimize for size.
1 Do mild speed optimizations.
2 Do more speed optimizations.
3 Do lots of speed optimizations (not recommended).

Note that only one command line switch can be used on a single compilation, and that each level of speed optimizations does everything the level below it does, and more. For more information, read the GCC manual.

The main reason for code to become buggy or not work after adding compiler optimizations is that it removes variables, or assumes that it doesn't have to reload variables because their value isn't changed in any other code (which isn't true for most components of kernels, which are hugely interdependent). To prevent this from happening, use the volatile keyword.

The Cache

The CPU's cache contains a very fast store of currently-used data. If an instruction references data that is already in the cache, it is going to be much faster than if it has to be read from general-purpose RAM. The change in speed, can vary due to memory access and other bus/ memory related instructions. To give a percentage, it varies from 200% ( in case it were from ram) to 400 % faster. however, the cache is not very big. On older processors it is in KB, but today it is mostly MB, varying from 1 - 8MB . The reason why a memory access can be slower, is that if you try to access a memory part, witch is not cached. That means that the CPU has to get that "area", even into the cache, or directly.

Piping

in the older days, where dual cores did not exist, and the CPUs were slow, they need to speed things up. of cause there are many ways to achieve this. Intel decided to use the Pipe idea, used in RICS CPUs and other high speed CPUs. The idea behind piping is that you can execute more instructions in only 1 cycle. This means that if you have 2 pipes ( 1 pipe = 1 instruction / cycle), you can execute 2 instructions in 1 time. Now there are only 1 big problem. How can that be possible if you change a register in the fist instruction, and then use it in the next?, the solution is bad because there is no other solution: wait until the first instruction has completed. So the upside of this is simply: you can increase the speed many times, but you can also make the code extremely slow. today, Intel says that their CPUs can have up to 6 pipes, so at a assembly level we can make the code up to 600 % faster, in case that we don't think about piping. here is a exampel for 2 pipes, the first is not optimized, the other is:

mov eax,0x0000aa55 ; don't think about the values, only the instruction order
mov esi,eax 
mov ebx,0x0000beef 
mov ecx,ebx
mov es,cx
mov edi,ebx
; and so could we continue all the day long...

now, can you see the problem ?, it should be very simple to image. however, here is a example witch is optimized for 2 pipes:

mov eax,0x0000aa55, the code does the same, but in a different order.   
mov ebx,0x0000beef 
mov esi,eax 
mov ecx,ebx
mov edi,ebx
mov es,cx

this example will run 3 times as fast as the unoptimized. The 2 pipes names is "V" and the "U" pipe, one thing to notice, is that the "U" pipe can NOT execute all types of instructions, only the most common instructions.

This page is a stub.
You can help the wiki by accurately adding more contents to it.

Links

Forum Topics

External