Saturday, January 11, 2014

Chapter:14 Chrono Support


'std::chrono' has been added in C++11 standard. It basically provides the time related operations in more flexible ways. Again key to this class is, it encapsulate all relevant information at one place. Frankly speaking I did find this part a bit difficult to understand. Nevertheless it provides us to write the piece of logic which can be used to measure any time related stuff in our code. Prior to that, there was no easy way to achieve this and we had use some system specific library/system calls to do this. Now all these can be done by just using standard library  interface. This is something which I always wanted to have in the standard.


It also provides the interface to change from C++ style type to C style type. This enables us to use good part of both the world (.i.e C and C++). The following two program demonstrate the basic usage of this 'std::chrono' library. Apart from that, these library can be used in  various places as time manipulation related operation are very common in non trivial software. Once we understand below progarm, we can check the other  facility of this library and accordingly we can start using those in  our work.



This program explains how we can write safe and better version of 'time.h' functions. We all know that these functions returns the pointer to static objects, which may be changed/overwritten by any other subsequent calls .


To improve this situation, we can write the wrapper function for these functions where after the call to these function, we do deep copy of those information into our local copy. Now we can provide the local copy to our caller which would always have the valid and consistent information.


The below program basically finds the current time using 'std::chrono' interface. After that we again use the 'std::chrono' interface to convert the C++ style type to C style data type. Now we can pass this data as argument to our wrapper function. These wrapper functions would basically provide us the current time in more human  readable format. These all stuff can be done in complete C style interface as well  and people had been using those interface since years. However, here I have tried to explain and write the better code in complete C++11 style. Choice is yours but personally I think C +11 style is safe and better code in this case. Hope it make  sense to reader.


//Code Begins

#include<iostream>
#include<thread>
#include<chrono>
#include<ctime>
#include<string>
using namespace std::chrono;

std::string get_ctime_to_ltime(const time_t* tp) {
    char* tmp=::ctime(tp);
    std::string output{tmp};
    return output;
}

std::string get_gmtime_asctime(const time_t* tp) {
    struct tm* gt=::gmtime(tp);
    char* tmp=::asctime(gt);
    std::string output{tmp};
    return output;
}

void chrono_component(void) {
    auto tp=std::chrono::system_clock::now();
    time_t cstyle_t=system_clock::to_time_t(tp);
    std::cout<<"Local Time: "<< get_ctime_to_ltime(&cstyle_t)
         <<std::endl;
    std::cout<<"GMT Time: "<<get_gmtime_asctime(&cstyle_t)
         <<std::endl;
}

int main(int argc,const char* argv[]) {
    chrono_component();
    return 0;
}

//Code Ends



When I run the above program, I get the following output.


//Console Output Begins

$ ./test
Local Time: Mon Nov 25 20:54:36 2013

GMT Time: Mon Nov 25 15:24:36 2013

//Console Output Ends





This is one of the better programs which I have written using complete C++11 standard. So I could not resist myself to add this program in my current book. As I have  mentioned in our discussion, time measurement is very important part in our day to  day activity. If we are working on performance improvement or we want to find out how efficient the code is, we should always measure our code instead of just going by our intuition.


The following 'timemeasure' class is small helper class written by me using the facility provided by 'std::chrono'. So whenever we want to measure the time duration, we should create the object of this class and 'start point()' method of this class. This would start the  measuring time. Once we are done, we should call the 'end point()' method of this class. The 'end point()' method would also provide the number of units of time elapsed to its caller.


The 'timemeasure' class is template on type 'Tprecision'. The default here is 'milliseconds'. If user wants to measure in any other precision, he should pass that while creating the object of this class. I have also done typedef for 'unit' for user convenient and how any standard class actually defines for us. However if we want to avoid these, we can always use 'auto'  instead of specific type. It would work without any problem.


In the current example, I have measured the time at three different places and with different precisions. As usual we need to create the object before the line from which we want to measure. Once we are done with our measurement, we need to stop our measurement. This would give us the number of unit in specified presicion. I use this program extensively wherever I want to measure my code performances. Hope that reader too would find this useful.



//Code Begins

#include<iostream>
#include<thread>
#include<chrono>
using namespace std::chrono;

template<typename Tprecision=milliseconds>
class timemeasure {
private:
    steady_clock::time_point tbegin{};
    steady_clock::time_point tend{};
    steady_clock::duration diff{};
public:
    typedef steady_clock::duration::rep unit;
    timemeasure() {}
    ~timemeasure() {}
    void start_point(void){
        tbegin=steady_clock::now();
    }
    unit end_point() {
        tend = steady_clock::now();
        diff = tend-tbegin;
        Tprecision  dur{};
        dur=duration_cast<Tprecision>(diff);
        unit val=dur.count();
        return val;
    }
};

void function_one(void) {
    std::this_thread::sleep_for(seconds(2));
}

void function_two(void) {
    std::this_thread::sleep_for(seconds(2));
    std::this_thread::sleep_for(microseconds(1000));
}

void chrono_component(void) {
    timemeasure<>  timer1;
    timer1.start_point();
    function_one();
    timemeasure<>::unit val1 = timer1.end_point();
    std::cout<<"Val1:"<<val1<<"\n";

    timemeasure<microseconds>  timer2;
    timer2.start_point();
    function_two();
    timemeasure<microseconds>::unit val2 = timer2.end_point();
    std::cout<<"Val2:"<<val2<<"\n";

    timemeasure<nanoseconds>  timer3;
    timer3.start_point();
    std::this_thread::sleep_for(microseconds(10));
    timemeasure<nanoseconds>::unit val3 = timer3.end_point();
    std::cout<<"Val3:"<<val3<<"\n";
}

int main(int argc, const char* argv[]) {
    chrono_component();
    return 0;
}

//Code Ends



When I run the above program, I get the following output.



//Console Output Begins

$ ./test
Val1:2000
Val2:2001242
Val3:80697

//Console Output Ends



No comments:

Post a Comment