home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TPOPTIMZ.ZIP / OPTIM.DOC
Encoding:
Text File  |  1987-02-01  |  15.7 KB  |  402 lines

  1.      This  file   is  a  summary/outline  of   the  technical  article
  2.      "Optimization Techniques" by Dr. Richard Reese which is one in
  3.      a colletion   of   articles   entitled:
  4.  
  5.            "Turbo   Pascal  Advanced Applications"
  6.              edited by Judie Overbeek
  7.             published by Rockland Publishing
  8.             190 Sullivan Crossroad
  9.             Columbia Falls, MT
  10.  
  11.      You  can contact  Rockland for  a free  brochure about  the
  12.      book.
  13.  
  14.      I  would  like  to  thank  the  publishers  at  Rockland for
  15.      allowing me to summarize the key points and include excerpts
  16.      from their  publication for educational purposes in the
  17.      Borland Programmer's Forum Online Seminar: "Optimizing
  18.      Turbo Pascal programs" :
  19.  
  20.      I like this article because it has some interesting and well
  21.      thought-out  code  optimization  techniques  (at  the Pascal
  22.      level) and feel it is  a good framework for discussion. This
  23.      summary is not all inclusive,  I spent more time on sections
  24.      I found  instructive  and  new,  and  briefly  (or failed to
  25.      mention  at all)  sections which  refer to  issues that have
  26.      appeared in a variety of publications, such as, how to set a
  27.      pointer to an array type to save data space. I encourage you
  28.      to get this book and read  the entire article as well as the
  29.      other excellent articles in the journal.
  30.  
  31.      I have  thrown in  my  own  comments and  embellishments and
  32.      attempt to make the distinction  between the article andthe
  33.      asides clear. If  I am unclear in this  regard, my apologies
  34.      to the author. If you have any questions send them to me Joe
  35.      Schrader [76703,4161] in the Online Seminar in section 2 (or
  36.      in section 4 after the seminar concludes).
  37.  
  38.      Optimization Issues : Speed versus Size, and Suboptimization
  39.  
  40.      Dr.  Reese  begins  by  stating  that  Turbo  Pascal  is  an
  41.      efficient compiler but  there are limits to what  a compiler
  42.      can do and a programmer  can perform techniques that improve
  43.      the performance  of a program   by an order  of magnitude or
  44.      better. Ok sounds promising.
  45.  
  46.      His most  important point in   the first section  is that a
  47.      program's  performance is  measured  in  terms of  speed AND
  48.      size.  In  addition  "there  is  almost  always  a trade-off
  49.      between the  execution speed of   a program and  the size it
  50.      requires." He points out that his emphasis in the article is
  51.      speed optimization, which is  usually most talked about, but
  52.      we  cannot  entirely  overlook  size  optimation. With Turbo
  53.      Pascal's  64K  limit,  some  algorithms  require  the use of
  54.      pointers  to  data  structures.  Since  pointer accesses are
  55.      slower than  regular variable references, a  program that is
  56.      not   optimized  for   size  can   have  a   degraded  speed
  57.      performance.
  58.  
  59.      Programming has been characterized  as the use of algorithms
  60.      and data  structures. Reese indicates  that when you  try to
  61.      decide  between  data  structures  and  the algorithmns that
  62.      manipulate them, there may be  some operations within a data
  63.      structure which are efficient and other operations which are
  64.      inefficient.  He  illustrates  this  point  by comparing the
  65.      performance  of an  array implementation  of lists  versus a
  66.      pointer  implementation. Some  operations are  quick on  the
  67.      array  implementation  and  others  faster  in  the  pointer
  68.      version.  The  key  is to  base design decisions  on  the
  69.      operations your program will do  most often. Since you don't
  70.      always  know how  your program  is going  to be  used, these
  71.      types of design decisions are not always clear-cut.
  72.  
  73.  
  74.      Optimization Techniques
  75.  
  76.      Dr. Reese lists three major classes of optimization techniques
  77.      (listed in order of importance):
  78.  
  79.        1) Algorithm/Data structure optimization
  80.        2) Code optimization
  81.        3) Hardware optimization
  82.  
  83.      Algorithm/Data Structure Optimization
  84.  
  85.      The choice  of a good  formula and data  structure obviously
  86.      has the greatest  impact on the speed of the  program but as
  87.      someone in the Seminar pointed out, there is not really much
  88.      to say about this topic. We can go through some classic sort
  89.      and search examples and refer to classic texts on algorithms
  90.      but in the  general case all you can say  is think the thing
  91.      through  and   pick  the  best-suited  algorithm   and  data
  92.      structure  before you  commit yourself  to writing  a lot of
  93.      code which may become obsolete.
  94.  
  95.      Hardware Optimization
  96.  
  97.      Once again, a hard disk  or a math co-processor will improve
  98.      performance  depending on  the nature  of your  program. But
  99.      what more can be said?
  100.  
  101.      When to optimize, and Save the old code
  102.  
  103.      This is  not a section   in the article,  but the sentiments
  104.      exist throughout. It  is important to get a  program working
  105.      to specifications  first, then optimize  it (if the  project
  106.      schedule  permits). There  are several  reasons listed below
  107.      (some of  which have been  pointed out by  others) which can
  108.      save many hours of frustration.
  109.  
  110.      The  first reason for not prematurely optimizing a routine
  111.      pretty much sums up the rest:
  112.  
  113.        1) Don't optimize a routine  that that may be thrown away.
  114.        Until  a program  is completed  you cannot  really be sure
  115.        that a  routine will be   used unchanged -  so don't waste
  116.        time optimizing code that may not be used.
  117.  
  118.        2) In  general, concerns about  how fast a  procedure runs
  119.        can get in the way of  the development process. Just as it
  120.        is  usuallly faster  to write  a program  in a  high-level
  121.        language than  in assembler, you should  be thinking about
  122.        solving  the problem  with a  well-structured approach and
  123.        not burden yourself with optimization issues at this stage
  124.        in development. There are  exceptions to this, however: If
  125.        the problem requires say a lot  of memory or must occur in
  126.        real  time,   it  may  be  impossible   to  abstract  from
  127.        optimization concerns.  I would say this  is the exception
  128.        rather than the rule, however.
  129.  
  130.        3) Optimized routines are often difficult to debug and cut
  131.        down on code-readability.
  132.  
  133.        4) An optimized routine may not necessarily be general. If
  134.        you  build routines  that will   end up  in libraries  for
  135.        several programs, make sure to  keep a copy of the general
  136.        solution before you scrap it for a speeded up version.
  137.  
  138.        Here  is  an  example  of  a  strip  of  code  that can be
  139.        optimized:
  140.  
  141.          ...
  142.  
  143.        repeat
  144.          BlockRead(F, Buf, SizeOf(Buf), BlocksRead);
  145.          ...
  146.        until BlocksRead = 0;
  147.  
  148.        Obviously,  you  can  cut  down  on  the  time it takes to
  149.        execute  this code  by replacing  the call  to SizeOf(Buf)
  150.        with a  constant or a  variable reference. But,  if I say,
  151.        change  the size  of the  variable during  the development
  152.        process, this could lead to a nasty bug if I do not change
  153.        the  constant. I  can also   use this  routine in  several
  154.        programs and  not worry about changing  anything. Flexible
  155.        routines  may not  always be  the fastest  running but are
  156.        useful in the development phase.
  157.  
  158.        5) It can  be more difficult to port  an optimized routine
  159.        to another language or machine.  This factor is of varying
  160.        importance to people.  But, the principle is, save  a copy
  161.        of the slow code.
  162.  
  163.  
  164.     Code Optimization
  165.  
  166.      Now that you have decided  you want to optimize your program
  167.      (despite all  of the above  warnings), Dr. Reese  points out
  168.      that  your time  is best   spent by  first optimizing  those
  169.      routines where your program is spending the most time. (This
  170.      makes a lot  of sense because the time you  have alloted for
  171.      optimization a  project is probably  almost nil). It  is not
  172.      always  obvious where  your program  spends its  time so you
  173.      should  get or  write a  profiler. (Ask  for information  on
  174.      available Turbo Pascal profilers in the online seminar).
  175.  
  176.      This  is the  most interesting   section of  the article.  I
  177.      especially like the  examples that show you how  to optimize
  178.      code  without  going  to  inline  code  or external assembly
  179.      language routines.
  180.  
  181.      While  high-level programming  decisions can  have the  most
  182.      effect on the performance of a program, code optimization is
  183.      important, and,  best of all,  there are GENERAL  techniques
  184.      that can  be applied to  your programs. In  this section Dr.
  185.      Reese shows  how to optimize simple  sequences of statements
  186.      as well as control structures  which, he points out, provide
  187.      many opportunities  for optimization. Note, that  with these
  188.      techniques  we are  optimizing for   speed and  much of  the
  189.      "optimized" code  will take more  code space. So  you should
  190.      measure  these   trade-offs  before  applying  any   of  the
  191.      techniques to your program (don't try this at home kids).
  192.  
  193.  
  194.       Simple Sequences of Programming Statements
  195.       (this  starts   on  page  10   of  Turbo  Pascal   Advanced
  196.       Applications in case you are reading along)
  197.  
  198.       Duplication or Effort
  199.  
  200.          A1 := B1 * C[i]*10;
  201.          A2 := B2 * C[i]*10;
  202.  
  203.       We can cut out the duplication of C[i]*10 with:
  204.  
  205.         T := C[i] * 10;
  206.         A1 := B1 * T;
  207.         A2 := B2 * T;
  208.  
  209.      It seems strange that  converting two programming statements
  210.      to three actually  saves execution time. But, let's  look at
  211.      what we've  done: We have  converted two calculations  of an
  212.      arithmetic  expression  to  one  calculation  and  added two
  213.      variable  references. Since,  in this  case (and  most), the
  214.      variable reference  takes much less processor  time than the
  215.      calculation, we have optimized this code for speed.
  216.  
  217.      This  technique, of  course, is  not  limited  to arithmetic
  218.      examples. Here is  a common example (at least  for me) using
  219.      strings. It uses a function  StripExt which removes the file
  220.      extension from a file name.
  221.  
  222.         BackFileName := StripExt(FileName) + '.BAK';
  223.         ErrorFileName := StripExt(FileName) + '.ERR';
  224.  
  225.      We here we  are calling the function StripExt  a second time
  226.      unnecessarily. Optimize it to this:
  227.  
  228.         RootName := StripExt(FileName);
  229.         BackFileName := RootName + '.BAK';
  230.         ErrorFileName := RootName + '.ERR';
  231.  
  232.      Here it is clearer why we save time with the second piece of
  233.      code. We  have cut two calls  to a function down  to one and
  234.      the time this saves  obviously outweighs the extra statement
  235.      in the code.
  236.  
  237.  
  238.      Reduction in Strength
  239.  
  240.      Reese's  point here  is  that  operations of  lower strength
  241.      execute faster, so replace
  242.  
  243.       j := i * 2;
  244.  
  245.     with
  246.  
  247.      j := i + i;
  248.  
  249.      Once again, it seems a  little odd that 2 variable references
  250.      on  the right  side of  the second  example, versus  1 in the
  251.      first, does  not   offset  the   time  difference   of  the
  252.      calculation, but it does.
  253.  
  254.      Another common  optimization technique alluded to  here (and
  255.      in many  other places) is that  SHL and SHR are  faster than
  256.      the equivalent multiplication operations.  We can go through
  257.      some  examples and  benchmarks in  the seminar  if anyone is
  258.      interested.
  259.  
  260.      Control Structures - Loop Constructs
  261.  
  262.      Duplication or Effort revisted
  263.  
  264.      It is plain  to see that the techniques  shown above produce
  265.      more dramatic  results when used inside  of loop constructs,
  266.      such  as, for,  repeat and   while loops.  Those of  you who
  267.      looked ahead probably saw that the earlier BlockRead example
  268.      can be optimized with the following:
  269.  
  270.          ...
  271.        NumBytes := SizeOf(Buf);
  272.        repeat
  273.          BlockRead(F, Buf, NumBytes, BlocksRead);
  274.          ...
  275.        until BlocksRead = 0;
  276.  
  277.      We have cut down duplication of effort by moving the call to
  278.      SizeOf outside  of the loop, or  as Dr. Reed says  "move the
  279.      invariant computations outside the body of the loop."
  280.  
  281.      Loop unrolling
  282.  
  283.      This is an  interesting technique that I would  not think of
  284.      doing unless I really needed to  tighten a loop. The idea is
  285.      to cut down  on the number of branches and  comparisons in a
  286.      loop by doing twice the work with each iteration.
  287.  
  288.      Here is the example Dr. Reese shows on page 11:
  289.  
  290.      i := 1;
  291.      while i <= 1000 do
  292.      begin
  293.        Sum := Sum + A[i];
  294.        i :=  i + 1;  { Oh come on we know that i := succ(i) is }
  295.                      { faster by now }
  296.      end;
  297.  
  298.      the  following  contortion  cuts  the  #  of comparisons and
  299.      branches in half:
  300.  
  301.      i := 1;
  302.      while i <= 1000 do
  303.      begin
  304.        Sum := Sum + A[i];
  305.        Sum := Sum + A[i + 1];
  306.        i :=  i + 2;
  307.      end;
  308.  
  309.      In general, this would be difficult for me to do without the
  310.      risk of bringing in incideous, off-by-one errors. But, if you
  311.      like  this  type  of  thinking,  all  the  better. Dr. Reese
  312.      goes on  to give more  interesting examples of  this type of
  313.      technique.
  314.  
  315.      The Sentinel
  316.  
  317.      This  technique  is  more  to  my  liking.  It  is  used for
  318.      searching  arrays for  a given  value. There  may be  a more
  319.      general application  of the technique,  but in any  event, I
  320.      like this type of thinking. Here is the code to be optimized
  321.      (it will probably look familiar):
  322.  
  323.     BEFORE
  324.  
  325.     i := 1;
  326.     while (A[i] <> Target) and (i <= Max) do
  327.       i := i + 1;
  328.     if i <= max then
  329.       { Target Found }
  330.     else
  331.       { Target not found }
  332.  
  333.     AFTER
  334.  
  335.     A[0] := target;
  336.     i := Max;
  337.     while A[i] <> Target do
  338.       i := i - 1;  {  How about i := pred(i)   }
  339.     if i = 0 then
  340.       { Target not found }
  341.     else
  342.       { Target found }
  343.  
  344.      The  "extra code"  here is  the check  (i <=  Max) in  every
  345.      iteration of the while loop. To  get around this, we put the
  346.      target  value in  the unused  0th element  of the  array (we
  347.      change the  type declaration to   make it 0  based) and loop
  348.      until the target is found, which is guaranteed to happen. We
  349.      are also sure that the code will  not go out of bounds so we
  350.      can cut our comparisons in half.
  351.  
  352.      Dr. Reese states  that for loops are faster  than repeat and
  353.      while loops, so, I will usually hack out a different method:
  354.  
  355.     for i := 1 to Max do
  356.       if A[i] = Target then
  357.         Exit;
  358.  
  359.    ... in the calling routine
  360.  
  361.     if i <= max then
  362.       { Target Found }
  363.     else
  364.       { Target not found }
  365.  
  366.  
  367.     Control Structures - Selection statements
  368.  
  369.     These are the if and case statements (with possible GOTO's
  370.     thrown in).  I will just mention a few of Dr. Reese's
  371.     points:
  372.  
  373.       - Use  a case statement  rather than an  if/else when there
  374.         are three or more choices. (Good, since this is also when
  375.         you should use a case statement to improve readability).
  376.  
  377.       - Put selections in a case or if/else statement in the
  378.         order of frequency you estimate they will be selected.
  379.  
  380.  
  381.  Conclusion
  382.  
  383.      This  article  goes  into  many  other  techniques  that can
  384.      improve  the performance  of a  program. However, techniques
  385.      such  as  the  use   of:  inline  code,  external  routines,
  386.      blockread  for file  I/O, pointers  to arrays  to save  data
  387.      space, etc.,  have appeared in other  publications and their
  388.      value in optimizing programs is obvious.
  389.  
  390.      I  hope Dr.  Reese's thought-provoking  article will promote
  391.      discussion in the Online Seminar.
  392.  
  393.      "See you there!"
  394.  
  395.         Joe
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.