home icon Home
Theme
⪆ 4 min read

Once upon a time, I was trying to write some code for some robot hardware’s serial communication part. I had a desktop pc, no memory restrictions (8GB RAM, i3 CPU etc.) and that particular program communicated with a microcontroller via USB(Fullspeed) or Serial with 115200 baudrate.

I had around 20 to 30 methods which used this communication function and because of that, I was really curious how its processing time affected the efficiency of the communication.

Only one instance of this function is running at the same time, meaning no mutex/semaphore. The question is… Which one of the following is faster?

1. Define first, use every time

...
private:
    struct timespec ctv1, ctv2;
    double time_diff;
    int serial_write_ret;
    int ret_val;
...
int MSerial::genAndSend_setInt32Command()
{
    genSum ( stm_buf_t );
    sem_wait ( &serial_mutex );
    // someFunctions();
    sem_post ( &serial_mutex );
    return ret_val;
}

2. Or allocate and deallocate every time

int MSerial::genAndSend_setInt32Command()
{
    genSum ( stm_buf_t );
    struct timespec ctv1, ctv2;
    double time_diff = .0;
    int serial_write_ret;
    int ret_val = TIMEOUT_ERROR_IN_SERIAL;

    sem_wait ( &serial_mutex );
    // someFunction();
    sem_post ( &serial_mutex );
    return ret_val;
}

Initially I was looking for answers online but I realised that I should examine the problem within its own environment. And wrote the following codes to test.

”Allocate - Deallocate every time” class:

class AllocEvery
{
public:

    int doSomething()
    {
        double pi, gold, ogh;
        std::string den_rit, jobs, bill;
        char c_str[64];

        pi   = 3.1415926535;
        gold = 1.6180339887;
        ogh  = 0.0000000033;
        ogh += pi;
        ogh += gold;
        jobs = "Being the richest man in the cemetery doesn't matter to me. Going to bed at night saying we've done something wonderful, that's what matters to me.";
        bill = "Your most unhappy customers are your greatest source of learning.";
        den_rit = "UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.";
    }
};

Then, Process only:

class ProcessOnly
{
public:

    double pi, gold, ogh;
    std::string den_rit, jobs, bill;
    char c_str[64];

    int doSomething()
    {
        pi   = 3.1415926535;
        gold = 1.6180339887;
        ogh  = 0.0000000033;
        ogh += pi;
        ogh += gold;
        jobs = "Being the richest man in the cemetery doesn't matter to me. Going to bed at night saying we've done something wonderful, that's what matters to me.";
        bill = "Your most unhappy customers are your greatest source of learning.";
        den_rit = "UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.";
    }
};

And, in main, I used these classes in the same way, and tried which one is faster;

int main ( int argc, char **argv )
{
    int max = 80 * 60 * 5; // Rate * Seconds * Minutes
    struct timespec time1, time2;
    double time_diff = .0;
    AllocEvery obj; /// ProcessOnly obj;

    clock_gettime ( CLOCK_MONOTONIC, &time1 );

    for (int i = 0; i < max; i++)
    {
        obj.doSomething();
    }

    clock_gettime ( CLOCK_MONOTONIC, &time2 );

    time_diff = time2.tv_sec - time1.tv_sec + ( time2.tv_nsec - time1.tv_nsec ) / BILLION;

//  std::cout << "Process only :: Elapsed time: " << time_diff << std::endl;
    std::cout << "AllocEvery :: Elapsed time: " << time_diff << std::endl;

return 0;
}

I’ve built two files by commenting-out the other: a.out and p.out. And then compared them:

ogh@ubuntu:~/C_denemeler/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.075384
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0741677
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.074426
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0740817
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0734898
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0747045
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0727975
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0772903
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./a.out
------------> Alloc - Dealloc Everytime:: Elapsed time: 0.0726992
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00806864
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00727956
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00202144
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00195636
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00203696
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00387936
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00276425
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00200299
ogh@ubuntu:~/C_Cpp_Examples/tryspeed_cpp$ ./p.out
------------>  Process only:: Elapsed time: 0.00207049

Here is a comparison:

Process only:: mean: 0.00356445 in seconds
Alloc Dealloc:: mean: 0.0743379 in seconds

Since these operations are done extremely fast in our CPUs nowadays, I had to introduce a period: 80 * 60 * 60 (Hz x Seconds x Minutes).

Full source is on github;

https://github.com/cosmicog/C_Cpp_Examples/tree/master/tryspeed_cpp

Share this post on:
Related Posts:
There are no related posts yet.