Mega Code Archive

 
Categories / Delphi / Examples
 

Performancetwo

Performance Tips and Tricks A good Design is much more important to how fast your application will execute. So my suggestion is: Switch optimization on and make sure your app is well designed. Then you'll probably have an application that is fast enough. ********************** Checkout: http://www.optimalcode.com/ Regards, Anthony Richardson anthony_r@sageautomation.com ********************** another tip is to minimise memory reallocations... EG reversing a string. function ReverseString (const Source :String):String; var I :Integer; begin Result := ''; for I := Length(Source) downto 1 do Result := Result + Source[I]; end; or alternatively function ReverseString (const Source :String):String; var I,SLen :Integer; begin SetLength(Result,Length(Source)); SLen := 1; for I := Length(Source) downto 1 do begin Result[SLen] := Source[I]; inc(SLen); end; end; no reallocations in the second as the length of Result is set once. ********************** While loops evaluate their end condition every iteration which will incur extra overhead in return for more powerful semantics. ********************** Optimising: 1: In most cases one hour of your time is worth more than 1000 hours of computer time. There is almost never a benefit in having the worlds fastest dialog box or smallest file loader. 2: Buy component sets (with source code) and save yourself a bundle. $100 of your time is what, 2-3 hours? It gets you the TurboPower basic utilities (string handling, dialogs etc) as one example. Or spend the time surfing the Delphi Super page and Torrys. Why reinvent the wheel? 3: Unless you profile it's very difficult to know where hand optimisation will give you a benefit. 4: The easiest hand optimisation I know of is religous use of parameter passing mechanisms. If at all possible make parameters const. Put integer and pointer parameters first in the list as they are eligable for being put in registers, and only the first three can have registers (in i86 machines anyway). Be aware of what you're passing (how bit it is, whether it's needed at all) 5: work on speeding up (reducing the use of) slow things first. Database access, file access and graphics in that order. It can be worth using a sorted TList and hash or binary search if you search things a lot. 6: put data in memory if speed is an issue. Trading memory for speed is often cheap and easy to code. Paul Jackson wrote: > 1) when passing parameters, use var, const or out as required > can speed up code, the use of the out parameter is more efficient More so in Pascal than Delphi AFAIK. Delphi has overheads that make this a minor point. Doubly indirect method calls sprint to mind, as well as the whole object model bundle. > 2) The string handling functions you get with Delphi are inefficient > 3) Use a profiler USE A PROFILER! I'll say that again: the cheapest code is the code that is never written, followed by code that is never executed. Optimising either type of code is a complete waste of effort. Better to come up with a good algorithm or design than an optimised bubble sort, I think. Example: I did a data transplation/import exercise transforming a couple of 100MB text files (fixed-width column records) into a 200+MB file using about 5 other files (30MB total) as secondary tables. Putting the secondary data in memory (TStringList.LoadFromFile) sped things up a lot. Profiling showed that about 90% of the time was spent finding keys in the secondary files. Since those files were sorted by primary key I made a TStringList descendent with a binary search in it. Then I put the keys into the list.Objects[] array as integers. That sped things up by about another 100x. In all I spent two days coding and about 2 hours executing. The first version (in memory, no binary search) looked like taking 48+ hours but took about 8 hours to code. Another 4 hours coding meant it took 1 hour to run, which turned out to be good because I also found data inconsistencies which meant regenerating the data files and re-running. The point is that a tiny amount of profiling and re-design made a huge difference, but no amount of optimised file handling could have given more than probably a 10% speed increase. Moz ********************** Use AnsiCompareText(str1, str2 ) = 0 as opposed to UpperCase(str1) = UpperCase(str2) This a significant difference in performance. The uppercasing allocates new string memory as well as the processing involved to traverse each string once before the comparison even occurs. ********************** One I have seen often is people not understanding the purpose of -1 being returned from IndexOf methods. The rule should always be compare with zero. The statement to check if an Item was not in a list should be: if List.IndexOf(Item)<0 then ... not if List.IndexOf(Item)=-1 then ... the same applies to comparison methods that return -1, 0, 1 - use comparisons with <0, =0 >0. ********************** These are nice tips, but pardon me if I must add that they only apply to your large Delphi projects on the ObjectPascal language level. And when you want/need the best efficiency, you need more than that. My paper on Delphi Efficiency (which started out as book on Borland Pascal efficiency, see http://www.drbob42.com/books/perform.htm) outlines a number of levels you can apply performance optimisation. Usually, this starts when your application is already slow and/or showing a performance problem. The first step then is: find the bottle-neck (really, only spend your efforts on that spot!). Step two is: check the algorithms and data structures (again, only on the places that are the bottle-necks). Step 3 is the first time you step down to the ObjectPascal feature coding level, but you *only* apply this step if step 2 failed or did not result in the required performance gain. However, while some of your tips may result in a somewhat better performance, a better algorithm (from O(N**2) to O(N log N) for example) can lead to an incredible performance enhancement - making the difference between a too-slow-to-use app and a useful app. And that's not even the last step, as you can read in my paper (which is almost an annual returning session at the Borland Conference, and of which one of the latest editions is available on my website at http://www.drbob42.com/delphi/perform.htm Groetjes, Bob Swart (aka Dr.Bob - www.drbob42.com) ********************** I think many of these would be handled by the optimiser anyway, but all too often, the optimiser screws up, and the only way to get your program to do what you tell it is to turn it off (this is my default setting for optimisation, and the first thing I check when I hit unexpected problems :) There are many simple ways (which I am sure you know about, but many others dont).... Here are some of my own: 1) when passing parameters, use var, const or out as required can speed up code, the use of the out parameter (according to a comment I recently found in the VCL) is more efficient that defining a function that does the same job. Each one has it's own benefit and drawbacks, so check the helpfile, but basically they beat standard params by not having to recreate the values for use in the target method... 2) The canned string handling functions you get with Delphi are VERY inefficient, and it is always worth checking out other implementations of the likes of Pos and copy from the net... 3) Use a profiler, there are many about, and can give you an idea what areas of your code is underperforming, and where your time would be best spent for the best time spent/results gained ratio... As for Davids suggestions: 1) Pred is an optimised method for subtracting 1 from a number, electronic processors are very bad at subtracting (thinking back to my university days, they have to jump though some serious hoops, to get the result, nines compliment and all that, where by Pred only needs to perform a simple bitwise operation) 2) Length(str)... Delphi stores a numeric value alongside every string allocated that determines the length of the string (check out "absolute" in the help file), this is the value Length returns, so I would imagine this is also quicker... 3) Counting down a for loop is more effiecient, that counting up (this is definately done by optimisation (badly)... 4) I imagine AnsiCompareText is quicker for long strings (converting each of those strings to uppercase is expensive if the first characters don't match... you need not have bothered converting the rest :) 5) Is number 5 quicker? I know the theory of the compiler having to create extra code to handle else's and that this is quicker, but I can see not benefit here.... I would agree with David that the optimiser is really bad...and as a rule, I always have it turned off...Does anyone know if there is a list of everything the optimiser is supposed to do? There is also a point where neat, understandable code can become more important than optimisation, so the few David are worth bearing in mind because they are still easy to read when used in code.... ********************** Use AnsiCompareText(str1, str2 ) = 0 as opposed to UpperCase(str1) = UpperCase(str2) Well, that is a good one. I forget about AnsiCompareText sooo often.... ********************** > > 3. Use AnsiCompareText(str1, str2 ) = 0 as opposed to UpperCase(str1) = > > UpperCase(str2) > >This a significant difference in performance. The uppercasing allocates new >string memory as well as the processing involved to traverse each string >once before the comparison even occurs. Absolutely; in a tight loop doing a lot of compares, all those UpperCases can add a huge amount of time. A small nitpick: AnsiCompareText does not perform the same case mapping as LowerCase and UpperCase; use "CompareText" if you want the equivalent equality test to using UpperCase.