Note:
Without looking at a short article, I guess the author should be a programmer or expert in the graphics field, introducing how to optimize C/C ++ code in the ray tracing program. It also has some reference significance. Of course, I do not agree with it or I do not fully understand it. Here, my rough translation is as follows:
1. Keep in mind the ahmdal Law
- Funccost indicates the running time percentage of the function func, and funcspeedup indicates the running coefficient of the function after optimization;
- Therefore, if the triangleintersect () function occupies 40% of the running time and you optimize it to make it run twice faster, your program runs 25% faster;
- This means that the less frequently used code does not need to be optimized too much (or is not optimized at all), such as the scenario loading process;
- That is, to make the code that is frequently called run more efficiently, while to keep the code that is rarely called run correctly;
2. Have the correct code first, and then optimize it.
- This does not mean that it takes 8 weeks to write a full-featured light tracker, and then 8 weeks to optimize it;
- It is optimized in multiple stages of your pipeline tracing program;
- If the code is correct and you know which functions are frequently called, the optimization is obvious;
- Locate the bottleneck and remove it (through optimization or Algorithm Improvement ). Generally, improving algorithms can significantly optimize bottlenecks-or even using an algorithm you didn't expect. It is a good practice to optimize the functions that you know will be frequently called;
3. People I know who can write very efficient code say they spend at least two times as much time optimizing Code as they write code.
4. Jump/branch statements are expensive, so you can minimize the cost at any time.
- In addition to stack storage operations, function calls also require two jumps;
- Iteration rather than recursion is preferred;
- For short functions, use inline to eliminate function overhead;
- Place the loop in the function (for example, change for (I = 0; I <100; I ++) dosomething (); to dosomething () in dosomething ());
- The long if... else if... statement chain takes a lot of jumps to end (except when testing each condition ). If possible, change to the switch statement. Sometimes the compiler can optimize the query and single-level jump in a table. If the switch statement is not possible, place the if statement that is most frequently accessed at the beginning of the statement chain;
5. Consider the order of array Indexes
- Arrays of two or more dimensions are stored in the memory in one dimension. This means that array [I] [J] and array [I] [J + 1] are adjacent (C/C ++ Code ), however, array [I] [J] and array [I + 1] [J] can be any distance from each other;
- Accessing continuous data in the physical memory can significantly speed up your code (sometimes an order of magnitude or even more );
- When the CPU loads data from the primary memory to the cache, it loads not only a single piece of data, but also the data to be requested, it also contains some adjacent data (a cache row ). This means that if array [I] [J] is in the CPU cache, array [I] [J + 1] may also be in the cache, however, array [I + 1] [J] may still be in the memory;
6. Considering command-level concurrency (IPL)
- Although many programs are still executed in a single thread, the modern CPU has been able to have significant concurrency on a single core. This means that a single CPU may also execute four floating point multiplication, wait for four memory requests, and execute the upcoming branch comparison operation.
- To make full use of this concurrency, a code block (such as in a jump statement) requires enough independent commands to make full use of the CPU;
- You can consider improving it by expanding the loop;
- This is also a good reason for using inline functions;
7. avoid or reduce the use of local variables
- Local variables are usually stored on the stack. If there are few, they can be stored in registers. In this case, the function not only benefits faster memory access to the data stored in the register, but also avoids the overhead of setting up a stack frame;
- However, do not declare all objects as global variables;
8. Reduce the number of function parameters
- The same reason as reducing local variables-they are also stored on the stack;
9. When passing parameters through a struct (including classes), use a reference instead of a value.
- In the ray tracing program, even if it is a simple structure such as vector, points, colors, and so on, I have never seen code that uses value transfer.
10. If you do not need the return value of a function, do not return
11. Try to avoid using transformation operations
- The instruction sets of integers and floating-point numbers are usually computed on different registers. Therefore, the transformation operation requires the copy operation;
- The short INTEGER (char and short) still requires a full-size register, and they need to be aligned to 32-bit or 64-bit before they are stored back to the memory, then it is converted to a smaller type;
12. Be careful when defining C ++ objects
- Use initialization (color C (black) instead of assigning values (color C, C = black), and the former is faster;
13. Make the default constructor of the class as lightweight as possible
- Especially the simple and frequently used classes (such as colors, vectors, points, etc );
- These default constructor are usually called when you do not pay attention to it, even if you do not want it at that time;
- Use to construct the initialization list (use color: color (): R (0), g (0), B (0) {} Instead of color: color () {r = G = B = 0 ;});
14. Try to use Shift Operators >>and <<, instead of integer multiplication and division.
15. Be careful when using the look-up table function
- Many people encourage the use of pre-computed value lookup methods for complex functions (such as trigonometric functions. This is often unnecessary for Ray Tracing programs. Memory lookup is very (increasingly) expensive, and recalculating trigonometric functions is often as fast as searching values from memory (especially when you consider that memory lookup will affect the CPU cache hit rate );
- In other cases, the lookup table may be very useful. For example, in GPU programming, the look-up table method is usually the preferred choice for complex functions;
16. For most class types, use the operator + =,-=, * =, And/=, instead of using + ,-,*,/
- This type of simple operation actually requires creating a temporary intermediate object with an anonymous name;
- For example, the vector v = vector (, 0) + vector (, 0) + vector (, 1) statement creates five unnamed, temporary vectors: vector, 0), vector (, 0), vector (, 1), vector (, 0) + vector (, 0), and vector (, 0) + vector (0, 1) + vector (0, 0, 1 );
- Better practice: vector V (, 0); V + = vector (, 0); V + = vector (, 1 ); in this way, only two temporary vectors are created: vector V (, 0) and vector (, 1 ), 6 function calls are saved (3 constructor and 3 destructor );
17. For the basic data type, use the operator +,-, *,/, and less + =,-=, * =, And/=.
18. Definition time of delayed local variables
- Defining an object always has a function call overhead (constructor)
- If an object is used only sometimes (for example, in an if statement), it is defined only when necessary, in this way, the constructor of the variable is called only when the variable is used.
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 object copy operation must use the suffix operator (which requires an additional constructor and a destructor), while the prefix operator does not generate a temporary object.
20. Use the template with caution
- The Optimization Methods for various existing instances may be different;
- The standard template library (STL) has been well optimized, but it is best to avoid using it if you plan to implement an interactive light tracker;
- By yourself, you can clearly understand the algorithm you want to use, and you will know the most effective way to use it;
- More importantly, my experience shows that debugging and compiling STL will be slow. This is usually okay unless you use the debug version for performance analysis. You will find that operations such as STL construction and iterator occupy more than 15% of the running time, which will make the output analysis results more chaotic.
21. Avoid dynamic memory allocation during computing
- The main advantage of dynamic memory is that it stores scenario data and other data, rather than modifying it during computing.
- However, in many (MOST) cases, system dynamic storage allocation requires the use of locks to control the access distributor. For multi-threaded applications that use dynamic memory, you may actually get a slower program because they need to wait for memory allocation and release.
- Even in a single-threaded program, allocating memory on the stack is more expensive than allocating memory on the stack. The operating system needs to perform some calculations to determine the size of the memory block.
22. Discover and make full use of useful information about your system memory cache
- Ü if the size of a Data Structure exactly fills up a cache row, you only need to read the entire class from the memory;
- Ü ensure that all data structures can be aligned to the cache boundary (If your data size and cache are 128 bytes, when one byte is in the same cache row and the other 127 byte is in the second cache row, the performance is still poor)
23. Avoid unnecessary data Initialization
- If you want to initialize a large block of memory, consider using the memset () function.
24. End loop judgment and function return as early as possible
- Consider the intersection of rays and triangles. It is common that rays and triangles do not overlap, so we can optimize them here;
- If you want to determine the intersection of rays and triangles, once the X-ray plane is negative, you can return immediately. This allows you to skip the calculation of the center of gravity coordinates at the intersection of a ray triangle. A huge victory! Once you are sure that there is no intersection, the intersection function should exit.
- Likewise, some cycles can be terminated early. For example, in the Light Shadow setting, the closest intersection is unnecessary. If any cross-Closed Loop is found, the result can be returned by the intersection function.
25. Simplify the formula on paper
- In many formulas, computation can always be canceled or in some special cases.
- The compiler cannot find the simplification, but you can. Eliminating some expensive operations in the internal loop can accelerate your program better than optimization elsewhere.
26. For integer, fixed point, 32-bit floating point, and 64-bit floating point, the difference between them is not as big as you think.
- Modern CPUs have the same computing throughput for floating-point operations and integer operations. Computing-intensive programs such as ray tracing mean that the difference between integer and floating-point operation costs is negligible, this means that you do not need to optimize the Integer Operation;
- Double-precision floating-point operations are not necessarily slower than single-precision floating-point operations, especially on 64-bit machines. I used to test the ray tracing algorithm on the same machine. The result is that sometimes double is faster than float,
27. Consider overwriting Your mathematical formula to eliminate expensive operations
- SQRT () functions can be avoided, especially when comparing the squares of values;
- If you need to divide X by multiple times, consider calculating 1/X and then multiplying. In the normalization operation of vectors (three Division operations), this was a great optimization, but recently I found it hard to say. However, it would be helpful if you divide it more times;
- If you execute a loop operation, remove the fixed computing in the loop out of the loop;
- Consider whether the value can be obtained in the calculated cyclic auto-increment (instead of calculated in each iteration). Original article: consider if you can compute values in a loop incrementally (instead of computing from scratch each iteration ).
- Http://www.cnblogs.com/lizhenghn/p/3969531.html
- Http://blog.sina.com.cn/s/blog_7cdd52580101chz7.html dm2-mean filtering Optimization
Optimization of embedded development-code optimization