Tips for optimizing C/+ + code

Source: Internet
Author: User

Source: http://www.cnblogs.com/lizhenghn/p/3969531.html

Description

Accidentally read a short essay, guessing that the author should be a programmer or an expert in the field of graphics, and describes how to optimize C + + code in a ray tracing program. There are some reference meanings, of course, some places I do not agree or say I do not fully understand, the original text here, my rough translation is as follows:

1. Keep in mind the Ahmdal law

                  

    • The funccost representation is the percentage of elapsed time of the function func, and funcspeedup is the operating coefficient of your optimized function;
    • So, if the function triangleintersect () consumes 40% of the running time, and after you optimize to make it run twice times faster, then your program can run 25% faster;
    • This means that infrequently used code does not need to be too much optimized (or not optimized at all), such as the scene loading process;
    • That is: let the frequently-called code run more efficiently, and keep the code for less calls running correctly;

2. First the correct code, and then do the optimization

    • This is not to say that it takes 8 weeks to write a full-featured Ray tracker and then spend 8 weeks to optimize it.
    • It is optimized in a number of stages in your pipeline tracking program;
    • If the code is correct and you know which functions will be called frequently, the optimization is obvious;
    • Then find the bottleneck and remove the bottleneck (through optimization or algorithmic improvement). In general, an improved algorithm can significantly optimize bottlenecks--perhaps even using an algorithm you didn't think of. It is a good practice to optimize the functions that you know will be called frequently;

3. People I know who can write very efficient code say that the time they spend optimizing code is at least twice times the time they write code.

4. Jump/Branch statements are expensive, no matter when possible to reduce the use of

    • Function call in addition to the stack storage operations, but also need to jump two times;
    • Preference for iterations rather than recursion;
    • If it is a short function, use inline to eliminate the function overhead;
    • Place the loop inside the function (for example, i=0;i<100;i++) dosomething (), instead of dosomething () in dosomething ());
    • Long If...else if...else If...else If ... A statement chain requires a large number of jumps to end (except when testing each condition). If possible, change the switch statement, and sometimes the compiler can have optimizations to find and single-level jumps in a table. If the switch statement is not possible, the most frequently-used if statement is placed at the beginning of the statement chain;

5. Consider the order of the array indexes

    • Arrays of two-D or more dimensions are still stored in memory as one-dimensional. This means that array[i][j] and array[i][j+1] are adjacent (c + + code), but Array[i][j] and array[i+1][j] can be at any distance away;
    • Accessing continuous data in physical memory can significantly speed up your code (sometimes an order of magnitude, or even more);
    • Now that the CPU is loading data from main memory into the cache, it is not just loading a single piece of data, but loading a chunk of data that contains both the data to be requested and some adjacent data (a cache line). This means that if ARRAY[I][J] is in the CPU cache, then array[i][j+1] is likely to be in the cache, but Array[i+1][j] may still be in memory;

6. Consideration of instruction-level parallelism (IPL)

    • Although many programs are still single-threaded, modern CPUs can have significant parallelism on a single core. This means that a single CPU may also perform 4 floating-point multiplication, wait for 4 memory requests, and perform the upcoming branch comparison operation
    • In order to take advantage of this parallelism, code blocks (such as in jump statements) require sufficient independent instructions to make the CPU fully available;
    • can be considered to improve by expanding the cycle;
    • This is also a good reason to use inline functions;

7. Avoid or reduce the use of local variables

    • Local variables are usually stored on the stack. If it is rare, it can be stored in registers. In this case, the function not only gets the benefit of faster memory access to the data stored on the register, but also avoids the overhead of establishing a stack frame;
    • However, do not declare all objects as global variables;

8. Reduce the number of function parameters

    • The same reason for reducing local variables-they are also stored on the stack;

9. Use a pass-through reference instead of a value when using a struct (including class) to pass a parameter

    • In the ray-tracing program, even simple structures like vectors, points, colors, and so on, I've never seen code that uses value passing.

10. If you do not need a return value for a function, do not return

11. Avoid using transformational actions whenever possible

    • The instruction set of integers and floating-point numbers is usually operated on different registers, so the transition operation requires a copy operation;
    • Short-shaping (char and shorts) still require a full-size register, and they need to be aligned to either 32-bit or 64-bit before being stored back into memory, before being converted to smaller size types;

12. Be careful when defining C + + objects

    • Use initialization (color C (black)) instead of assignment (color c, c = black), while the former is faster;

13. Make the class's default constructor as lightweight as possible

    • Especially that simple, often used class (for example, colors, vectors, dots, etc.);
    • These default constructors are usually called when you are not aware of them, even when you do not wish to do so;
    • Use the construct initialization list (using Color::color (): R (0), g (0), B (0) {} instead of Color::color () {r = g = b = 0;});

14. Use shift operators >> and << as much as possible instead of integer multiplication and division

15. Use the check list function carefully

    • Many people encourage the use of pre-computed tabular methods for complex functions, such as trigonometry. This is often not necessary for Ray Tracer applications. Memory lookups are very (increasingly) expensive, and recalculation of trigonometric functions tends to be as fast as finding values from memory (especially when you consider that memory lookups affect CPU cache hit ratios);
    • In other cases, it may be very useful to look up a table. For example, in GPU programming, the look-up method is usually the first choice of complex function;

16. For most class types, use Operators +=,-=,*= and/=, with less +,-,*,/

    • This kind of simple operation actually needs to create an anonymous, temporary intermediate object;
    • For example the vector v = vector (1,0,0) + vector (0,1,0) + vector (0,0,1) statement creates 5 unnamed, temporary vector:vector (1,0,0), Vector (0,1,0), Vector ( 0,0,1), vector (1,0,0) + vector (0,1,0), and Vector (1,0,0) + vector (0,1,0) + vector (0,0,1);
    • Slightly better approach: Vector V (1,0,0); v+= Vector (0,1,0); v+= Vector (0,0,1); This creates only 2 temporary Vector:vector V (1,0,0) and Vector (0,0,1), saving 6 function calls (3 constructs and 3 destructors);

17. For the base data type, use the operator +,-,*,/with less +=,-=,*= and/=

18. Delay the definition time of a local variable

    • Defining an object always has a function call cost (that is, the constructor)
    • If an object is used only sometimes (such as inside an if statement), it is defined only when necessary, because it is only used when the variable is in use to invoke its constructor

19. For objects, use the prefix operator (++obj) instead of the suffix operator (obj++)

    • This may not be a problem in your ray-tracing program.
    • The copy operation of an object must use the suffix operator (which requires an extra call to a construct and a destructor), and the prefix operator does not produce a temporary object

20. Use templates with caution

    • The optimization methods of various examples may be different;
    • The Standard Template Library (STL) is well optimized, but if you're going to implement an interactive Ray tracker, it's best to still avoid it;
    • By self-realization, you can clearly understand the algorithm to use it, you will know the most effective way to use;
    • More importantly, my experience shows that debugging and compiling STL will be slow. Usually this is fine, unless you use the debug version for profiling. You will find that the STL constructs, iterators, and other operations will take up more than 15% of the elapsed time, which will make the output more confusing.

21. Avoid dynamic memory allocations during the calculation

    • The main advantage of dynamic memory is that it stores scene data and other data, rather than modifying it during the calculation
    • However, in many (most) cases the system dynamic storage allocation requires the use of locks to control the access allocator. For multi-threaded applications that use dynamic memory, you may actually get a slower program due to the need to wait for allocation and release of memory through these additional processing
    • Even in a single-threaded program, allocating memory on the heap is more expensive than allocating it on the stack. The operating system needs to perform some calculations to determine the size of the block of memory that is required.

22. Discover and make the most of useful information about your system memory cache

    • ü If a data structure is exactly the size of a cache row, processing the entire class only needs to be read from memory;
    • ü Ensure that all data structures are aligned to the cache boundary (if your data size and cache are 128 bytes, then the performance is still bad when 1 bytes are in one cache row while the other 127 bytes in the second cache row)

23. Avoid unnecessary data initialization

    • If you want to initialize a chunk of memory, consider using the memset () function

24. End the Loop judgment and function return as early as possible

    • Consider the intersection of rays and triangles. The common case is that the rays and triangles do not intersect, so this can be optimized;
    • If you want to judge the intersection of the Ray and the triangle, once the T-value Ray plane is negative, you can return immediately. This allows you to skip around half of the light triangle intersection point of gravity coordinate calculation. A huge victory! Once you're sure there's no intersect, the intersection function should exit.
    • Similarly, some loops can be ended early. For example, in a Ray shadow setting, the closest intersection is unnecessary. As soon as any cross-closed loop is found, the intersection function can be returned

25. First simplify the formula you use on paper

    • In many formulas, it is always possible, or in some special cases, to cancel the calculation
    • The compiler cannot find these simplifications, but you can. Eliminating the expensive operations in some inner loops can speed up your program more than your optimizations elsewhere

26. For integers, fixed-point numbers, 32-bit floating-point numbers, and 64-bit floating-point numbers, the difference between them is not as big as you might think.

    • Modern CPUs with floating-point and integer operations actually have the same computational throughput, such as ray tracing, a computationally intensive program that means that the difference between integer and floating-point arithmetic costs can be negligible, which means you don't need to do some optimizations to use integer arithmetic;
    • Double-precision floating-point arithmetic is not necessarily slower than single-precision floating-point calculations, especially on 64-bit machines. I used to test the ray-tracing algorithm on the same machine, and the result is that sometimes using a double is faster than using float all.

27. Consider eliminating expensive operations by rewriting your math formula

    • The sqrt () function is usually avoidable, especially if the squared value of the comparison is equal;
    • If you need to divide by X repeatedly, consider calculating 1/x and multiplying. In the normalization operation of the vector (3 division), which was once a great optimization, but recently I found it hard to say. However, if you divide the number of times evenly, it is still useful;
    • If you perform a loop operation, move those calculations that are fixed in the loop out of the loop;
    • Consider whether you can get a value in the calculation loop increment (not every iteration), original: Consider if you can compute the values in a loop incrementally (instead of the computing from SCR Atch each iteration).

Tips for optimizing C/+ + code (GO)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.