Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ print progress with minimal impact on runtime

I have a C++ program with a long running loop. It has about 500000 iterations. I'd like to print the progress every 5%.

What I have so far is below. Problem with this is that it will keep writing the same line (0%, %5 etc) over and over. This is because after truncating the percent to an integer there are 1000's of iterations that will hit upon a multiple of 5. This makes the program noticeably slower.

Conversely, if I don't truncate to an integer, then the result of percent % 5.0 is unlikely to be precisely 0.

How can I print a progress indicator with the minimum possible impact on runtime?

// Counters for progress indicator
int i = 0;
float totalWindows = (float)(win.nX * win.nY);
int percent;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    percent = (i / totalWindows) * 100;
    if (percent % 5 == 0)
    {
        std::cout << "\r" << std::string(percent/5, '|') << percent << "%";
        std::cout.flush();
    }



}

EDIT: Thanks for the answers. I have gone with christophes' which just came to the least number of instructions. It shaved 25% of runtime, so pretty significant!

like image 435
jramm Avatar asked Oct 20 '22 04:10

jramm


2 Answers

Considering that totalWindows seems to remain unchanged, and integer increments/decrements will probably be faster than a lot of double operations with conversion to int, I propose:

// Counters for progress indicator
int i = 0;
float totalWindows = (float)(win.nX * win.nY);
int increment5 = 0.05 * totalWindows; // how many iterations does 5% represent ? 
int countdown = increment5;   // decrement countdown instead of modulo
int percent5 = 0;  // number of elements in the progress bar (1 means 5%)

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    if (--countdown == 0)
    {
            percent5++;
            std::cout << "\r" << std::string(percent5, '|') << percent5*5 << "%";
            countdown = increment5;  
            std::cout.flush();
    }

}

If you fear that the cumulative roundings would not be acceptable for displaying the progress, you could always opt to calculate the exact value in the if-block: the calculation would be performedonly once every 5% instead of at each iteration.

like image 157
Christophe Avatar answered Oct 21 '22 23:10

Christophe


How about:

int step = 5;
int nextPrint = step;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    percent = (100 * i) / totalWindows;
    if (percent >= nextPrint)
    {
        std::cout << "\r" << std::string(percent/5, '|') << percent << "%";
        std::cout.flush();
        nextPrint += step;
    }
}

BTW: Why do you have totalWindows as a float? That also hurts performance. If the number of iterations are 500000 an 32 bit int should be sufficient.

Another and better approach because percent isn't calculated in every loop:

const int percentPrint = 5;
int step = totalWindows / (100/percentPrint);
int nextPrint = step;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    if (i >= nextPrint)
    {
        percent = (100 * i) / totalWindows;
        std::cout << "\r" << std::string(percent/percentPrint , '|') << percent << "%";
        std::cout.flush();
        nextPrint += step;
    }
}
std::cout << "\r" << std::string(100/percentPrint , '|') << percent << "%";
std::cout.flush();
like image 34
Support Ukraine Avatar answered Oct 22 '22 00:10

Support Ukraine