As a Beginner, I am concerned with
The primary emphasis here is upon helping the beginner to make code
which executes fast.
Thus, do not optimize user input code. Also, common CRT displays
update at 30-100 Hz, so your output code does not need to be optimized
beyond a clearly defined limit.
The implication of the idea "optimize only frequently executing code"
is that you need to know your program and what code is executed when.
I don't find it at all helpful to use profilers. Some people find them helpful to get a general trend of what their code is doing. I think that beginners should use profilers, but there will also come a time when they only tell you what you already know.
quicker methods
write good code
examine code -- loop invarient
blah blah
look at output of compiler
(assembly language or intermediate code)
I find the best timing information by timing one (1) iteration of a small piece of code with a microsecond timer. (Faster than 1 us is good, if you can get it, but slower than 1ms doesn't do much good in my mind.) The basic code snippet would be
before = usec_time();
{do something}
after = usec_time();
printf("duration = %ld", after - before);
Note that the time stamp is sampled before the output statement.
This doesn't matter much here in a C language example, but can make quite
a difference in other languages. Avoid the construction print("duration
= ", usec_time() - before) especially when using an interpreter.
Take, for example, the code
MAX = 10
index = 1
while (index <= MAX)
total = total + 1
do stuff
index = index + 1
endwhile
as compared to
MAX = 10
index = 1
while (index <= MAX)
do stuff
index = index + 1
endwhile
total = total + MAX
Knowing what code to put inside vs. outside of the loop is more a matter of habit rather than sitting down and thinking for a few hours. Note that sitting down and thinking is often a good idea. (I try to think every now and then.) Some compilers will handle this simple case for you. More complicated cases cannot be handled by the compilers -- specifically when a function is being called. This is because you may know that the function is returning a constant value; but, the compiler doesn't know that fact.
Take, for example, the code
MAX = 10
index = 1
while (index <= MAX)
total = total + sin(alpha)
do stuff
index = index + 1
endwhile
as compared to
MAX = 10
index = 1
while (index <= MAX)
do stuff
index = index + 1
endwhile
total = total + MAX * sin(alpha)
where recomputing the sine several times is easily avoided.
The idea of a lookup table is that not only do you compute a value once and then use it several times later, but also that you can quickly access the value by using an array.
The drawback of lookup table isn't really the space of the array (although
that's a good point). The drawback is the complexity of the code.
You just can't optimize everything by hand -- the best use of lookup tables
are the ones which are automatically performed for you -- compiler optimizations
for switch statements.
The "turn on all optimizations" option may actually not turn on absolutely
all optimizations. For example, "register aliasing" optimizations
are probably not turned on; also, the compiler may want to optimize for
size -- I prefer to optimize for speed.
Compilers have bugs. Turning optimizations on (or off!) may make
(more) bugs show up in the compiler. That doesn't mean you turn optimizations
off; but rather, you need to retest the code when changing the optimization
level. The best way to find the source of a bug (when the compiler
flags make a bug show up) is to do a binary search. More about binary
searches and debugging in the debugging pages.
By the way, don't write lexical analysis and parsing code by hand --
just get better code generators. For example, the FLEX program can
generate much faster lexical analyzers than LEX does. But a better
optimization than both of these programs is to write your lexical specification
"the right way." More about optimizing lexical analysis in
the advanced pages.
switch (code_number)
{
case 1:
answ = "one";
break;
case 2:
answ = "two";
break;
case 3:
answ = "three";
break;
case 4:
answ = "four";
break;
default:
answ = "
break;
}
Compiler Optimizations
Turn them on.
know what library code really does
in-line functions
substituting utilities for expertise
profilers
substituting hardware for expertise
buy a faster machine
Use code generators
LEX and YACC are the most famous code generators. Learn about them
and use them when processing textual input.
Buy pieces of software that you can put together to get some or all of
the desired result.
(c) Copyright 1998 by John Muczynski. All Rights Reserved.
Stosh@nospam.lycosmail.com