250 likes | 474 Views
Code Tuning Strategies and Techniques. CS480 – Software Engineering II Azusa Pacific University Dr. Sheldon X. Liang. Code Tuning Strategies and Techniques. Overview Performance and Code Tuning Introduction to Code Tuning Common Sources of Inefficiency Measurement Iteration
E N D
Code Tuning Strategies and Techniques CS480 – Software Engineering II Azusa Pacific University Dr. Sheldon X. Liang
Code Tuning Strategies and Techniques • Overview • Performance and Code Tuning • Introduction to Code Tuning • Common Sources of Inefficiency • Measurement • Iteration • Code-Tuning Techniques • Checklist & Summary
Performance and Code Tuning cont. • Operating-system interactions • Inefficient operating system routines • Compiler generated system calls • Code compilation • Good compilers optimize code speed • Hardware • New hardware may be cheaper than optimizing code • Code tuning (Lastly) • Practice of modifying correct code in ways that make it run more efficiently
Introduction to Code Tuning • More lines of code = less efficient - FALSE • You should optimize as you go – FALSE • Make it work correctly first • What do you want to tune for? • Code Size versus Speed • Use a worker thread • The appearance of performance
Introduction to Code Tuning • When to tune • Jackson's Rules of Optimization: Rule 1. Don't do it. Rule 2 (for experts only). Don't do it yet—that is, not until you have a perfectly clear and unoptimized solution. —M. A. Jackson • Use compiler optimization • Write clear code • Let the compiler to the optimizing
Common Sources of Inefficiency • Input / Output Operations • In memory operation much faster than disk access • Organize and minimize I/O operations • Paging • Operation that causes the operating system to swap pages of memory is much slower than an operation that works on only one page of memory for ( column = 0; column < MAX_COLUMNS; column++ ) { for ( row = 0; row < MAX_ROWS; row++ ) { table[ row ][ column ] = BlankTableElement(); }} for ( row = 0; row < MAX_ROWS; row++ ) { for ( column = 0; column < MAX_COLUMNS; column++ ) { table[ row ][ column ] = BlankTableElement(); }}
Common Sources of Inefficiency • System calls • Calls to system routines are often expensive. • Context Switch • Possible Solutions • Write your own services. • Avoid going to the system. • Work with the system vendor to make the call faster. • Interpreted languages • Interpreted languages exact significant performance penalties • If performance matters, don’t use them
Measurement • Measure your code to find the hot spots • You don’t know if or how much your improving if you don’t measure • Measurement needs to be precise • QueryPerformanceCounter – Windows • Only measure the code your tuning
Iteration • Iteration • Multiple techniques may be necessary • Cumulative effect of tuning
Code-Tuning Techniques • Logic • Stop Testing When You Know the Answer negativeInputFound = false; for ( i = 0; i < count; i++ ) { if ( input[ i ] < 0 ) { negativeInputFound = true; break; } } • Consider order of evaluation • if ( 5 < x ) and ( x < 10 ) then ...
Code-Tuning Techniques • Order Tests by Frequency • Arrange tests so that the one that's fastest and most likely to be true is performed first Select inputCharacter Case "A" To "Z", "a" To "z“ ProcessAlpha( inputCharacter ) Case " “ ProcessSpace( inputCharacter ) Case ",", ".", ":", ";", "!", "?“ ProcessPunctuation( inputCharacter ) Case "0" To "9“ ProcessDigit( inputCharacter ) Case "+", "=" ProcessMathSymbol( inputCharacter ) Case Else ProcessError( inputCharacter ) End Select
Code-Tuning Techniques • Compare Performance of Similar Logic Structures • Test from case statement versus if-then-else logic. • This example illustrates the difficulty of performing any sort of "rule of thumb" to code tuning • There is simply no reliable substitute for measuring results.
Code-Tuning Techniques • Loops • Minimizing the Work Inside Loops • One key to writing effective loops is to minimize the work done inside a loop for ( i = 0; i < rateCount; i++ ) { netRate[ i ] = baseRate[ i ] * rates->discounts->factors->net; } quantityDiscount = rates->discounts->factors->net; for ( i = 0; i < rateCount; i++ ) { netRate[ i ] = baseRate[ i ] * quantityDiscount; }
Code-Tuning Techniques • Loops • Strength Reduction • Reducing strength means replacing an expensive operation such as multiplication with a cheaper operation such as addition For i = 0 to saleCount – 1 commission( i ) = (i + 1) * revenue * baseCommission * discount Next incrementalCommission = revenue * baseCommission * discount cumulativeCommission = incrementalCommission For i = 0 to saleCount – 1 commission( i ) = cumulativeCommission cumulativeCommission = cumulativeCommission + incrementalCommission Next
Code-Tuning Techniques • Use the Fewest Array Dimensions Possible • Conventional wisdom maintains that multiple dimensions on arrays are expensive. • If you can structure your data so that it's in a one-dimensional array rather than a two-dimensional or three-dimensional array, you might be able to save some time
Code-Tuning Techniques • Minimize Array References • Advantageous to minimize array accesses • The reference to discount[ discountType ] doesn't change when discountLevel changes in the inner loop for ( discountType = 0; discountType < typeCount; discountType++ ) { for ( discountLevel = 0; discountLevel < levelCount; discountLevel++ ) { rate[ discountLevel ] = rate[ discountLevel ] * discount[ discountType ]; } }
Code-Tuning Techniques • Minimize Array References • Move discount [discountType] out of the inner loop so that you'll have only one array access per execution of the outer loop for ( discountType = 0; discountType < typeCount; discountType++ ) { thisDiscount = discount[ discountType ]; for ( discountLevel = 0; discountLevel < levelCount; discountLevel++ ) { rate[ discountLevel ] = rate[ discountLevel ] * thisDiscount; } }
Code-Tuning Techniques • Use Caching • Caching means saving a few values in such a way that you can retrieve the most commonly used values more easily than the less commonly used values • You can cache the results of time-consuming computations too public double Hypotenuse( double sideA, double sideB ) { // check to see if the triangle is already in the cache if ( ( sideA == cachedSideA ) && ( sideB == cachedSideB ) ) { return cachedHypotenuse; } // compute new hypotenuse and cache it cachedHypotenuse = Math.sqrt( ( sideA * sideA ) + ( sideB * sideB ) ); cachedSideA = sideA; cachedSideB = sideB; return cachedHypotenuse; }
Code-Tuning Techniques • Expressions • Much of the work in a program is done inside mathematical or logical expressions. • Complicated expressions tend to be expensive • Exploit Algebraic Identities • Use algebraic identities to replace costly operations with cheaper ones. • The following expressions are logically equivalent: not a and not b not (a or b)
Code-Tuning Techniques • Initialize at Compile Time • If you're using a named constant or a magic number in a routine call, that's a clue that you could pre-compute the number unsigned int Log2( unsigned int x ) { return (unsigned int) ( log( x ) / log( 2 ) ); } • Replace log(2) with a constant
Code-Tuning Techniques • Eliminate Common Subexpressions • If an expression is repeated several times, assign it to a variable rather than re-computing in several places. payment = loanAmount / (( 1.0 - Math.pow( 1.0 + ( interestRate / 12.0 ), -months ) ) / ( interestRate / 12.0 ) ); • interestRate / 12.0 could be a variable
Code-Tuning Techniques • Routines • Good routine decomposition is best for well tuned code • Small, well-defined routines save space • Take the place of doing jobs separately in multiple places • You can re-factor code in one routine and thus improve every routine that calls it • Small routines are relatively easy to rewrite in a low-level language
Code-Tuning Techniques • Routines • Rewrite Routines Inline • Code executes “in-place” versus calling a routine • Less advantage with newer compilers and computers • Recoding in a Low-Level Language • If you're coding in C++, the low-level language might be assembler. • If you're coding in Python, the low-level language might be C.
Summary of the Approach to Code Tuning • Develop the software by using well-designed code that's easy to understand and modify. • If performance is poor, • Save a working version of the code so that you can get back to the "last known good state." • Measure the system to find hot spots. • Determine whether the weak performance comes from inadequate design, data types, or algorithms and whether code tuning is appropriate. If code tuning isn't appropriate, go back to step 1. • Tune the bottleneck identified in step (c). • Measure each improvement one at a time. • If an improvement doesn't improve the code, revert to the code saved in step (a). (Typically, more than half the attempted tunings will produce only a negligible improvement in performance or degrade performance.) • Repeat from step 2.