"Programming techniques to improve C + + performance" Reading note 2--tracking instances

Source: Internet
Author: User

"The end of the paper is light."


The trace described here refers to the process of tracking the program. Here is a discussion of tracing, which is designed to take advantage of efficient tracking of code, so that the trace does not increase the additional overhead of the source program as much as possible.

The trace here is actually very intuitive, that is, along the path of the program running, how to print out the program of each stage of the log information of the state of operation. Therefore, how to track code is a core issue. Improper tracking methods can lead to increased operational overhead. So how to design efficient tracking technology is a good way for us to learn how to write efficient C + + code.

Given the object-oriented nature of C + +, the most straightforward way to define a simple trace class is to print the state information of the program to a log file, where the programmer can use an object that defines a trace class in each program segment that needs to be tracked, printing the wrong information at the entrance and exit of the function. The ideal trace is to completely eliminate the overhead of performance in the Trace method, which is to put the trace call in the #ifdef的条件编译的块内. Like what:

#ifdef Trace T ("MyFunction"); T.debug ("Some debug Information"); #endif

The above code uses conditional compilation to track the program, so the biggest disadvantage of the tracking technology is that it has to be recompiled to open and track the technology , but this is only for free open source software. Unless you are willing to open your own code to the user to use. Therefore, we need to open the interface to the user, that is, conditional selection of whether to open the trace, that is, to check the status of the tracking and then record the tracking information.

For example:

void Trace::d ebug (String &word) {if (active) {//This record information}}

The intent of the program here should be to say that after the problem is determined, the tracking function is turned on, and the tracking default is inactive, so that we can ensure that the program is performing at its best performance, but it backfired, such as the following code:


T.debug ("t =" + itoa (x));

This typical trace statement can lead to serious performance problems, even if we turn off the program's tracking function, the amount of computation implied by this statement is absolutely negligible:

1 Create a temporary string object for "x="

2 Call function Itoa;

3 The character pointer returned from ITOA creates a temporary object of string

4 Connect the above two strings to construct the third temporary string object.

5 destructors for these three temporary objects are called when a debug call returns.


Based on this, it is necessary to construct a performance-efficient tracking function. Here's a step-by-step explanation:

For the tracking of a function, it is roughly the following code:

int myFunction (int x) {string name = "MyFunction"; Trace t (name);//do somethingstring meminfo = "more interesting info"; T.debug (moreinfo);} Class Trace{public:trace Trace (const string &); ~trace (); void debug (const string &name); static bool active; Private:string Thefunctionname;}; The Trace constructor is roughly the same: inline trace::trace (const string &name): Thefunctionname (name)? {if (active) {cout << name << Endl;}} Debug is used to print some additional information: inline void Trace::d ebug (const string &info) {if (active)  cout << info << Endl;} Inline Trace::~trace () {if (active) cout << "Exit" << Endl;}

However, the frequent creation and destruction of a large number of trace temporary objects in the program increases the cost of the program dramatically.


First, we need to analyze the above code, we set the constructors and destructors to inline to reduce the cost of the function call, and then we pass the function object in order to reduce the cost of parameter passing the use of reference value, first of all, the code itself is efficient, But after we joined the tracking we did a lot of things we shouldn't do, resulting in a decrease in performance.

Here is a simple test: first define a simple function:

void increment (int x) {return x + 1;}

After adding trace information to the function, the function is roughly:


int increment2 (int x) {    string name = "Increment2";    Trace t (name);    T.debug ("Enter ...");    return x+1;}
The complete code is:
#include <iostream> #include <string>using namespace std;int increment (int x) {return x+1;} Class Trace{public:inline Trace (const string &_name): Name (_name) {if (active) cout << "Ente    R function "<< name <<" ... "<< Endl;    } inline ~trace () {if (active) cout << "Exit ..." << Endl;    } inline void Debug (const string &msg) {if (active) cout << msg << Endl;    }private:string name;   static bool active;    };bool trace::active = true;int increment2 (int x) {string name = "Increment2";    Trace t (name);    T.debug ("Enter ..."); return x+1;}    int main (void) {int x = 0;    clock_t Start,finish;    Double total=0;    start = Clock ();    for (int i=0;i<1000000;++i) Increment2 (x);    finish = Clock ();    Total = static_cast<double> (Finish-start)/clocks_per_sec;    start = Clock (); for (int i=0;i<100000000;++i) increment (x);    finish = Clock ();    Total = static_cast<double> (Finish-start)/clocks_per_sec;    cout << "Running time =" << total << "s." << Endl;    cout << "Running time =" << total << "s." << Endl; return 0;}



We have already mentioned that the extra performance overhead in the above code comes from the creation and revocation of a string temporary object, where we always have the overhead of whether or not we have the trace feature turned on, and the following improvements can reduce overall performance overhead:

1 replaces the string object with a char pointer so that only the character array is created to hold the pointer if active is true.

2 It is not recommended to use the trace function for some short, frequently called functions , since the execution time of the function itself is relatively short, and the added statement has a large effect on the execution of the whole function. Imagine that a trace statement that adds a few lines to a function with only two rows and a trace statement in a hundreds of-line program might run a double for a short function, but the effect on a hundreds of-row function can be negligible.


Summarize:

In any program that needs to be traced, it is important to write efficient tracking code so that the performance of the program is not affected by trace. It is important to pay attention to some hidden overhead , such as the creation and revocation of temporary objects, as well as the use of reference values for functions, and short functions as inline as possible to reduce the overhead of function calls. All in all, try to avoid the introduction of trace to cause the performance of the program to change in order of magnitude.








"Programming techniques to improve C + + performance" Reading note 2--tracking instances

Related Article

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.