Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Optimization problems with std::array maybe due to RVO

velvia
Beginner
635 Views

Hi,

I discovered a source of slowdown in my program, due to the usage of std::array. To gain a better understanding of what was going on, I have used my own implementation of std::array, and the slowdown disappeared. Unfortunately, I can't show you the program I am working on due to some non disclosure agreement. But I've managed to track down the problem and put it in a simple file.

When you compile the file shown below with

icpc -c -std=c++11 -Ofast -xHost -ansi-alias -qopt-report=2 ode.cpp -o ode.o

and look at the optimization report, the generated function is

ode(StaticVector<double, 2UL> *, const StaticVector<double, 2UL> &)

But if you comment out what is in between the "culprit" comments, all the constructors and assignements, the function does have a new signature

ode(const StaticVector<double, 2UL> &)

My guess is that it has to do with return value optimization. Could you please explain me why we have such a difference?

Best regards,

Francois

#include <cstddef>
#include <utility>
#include <cmath>

template <typename T, std::size_t n>
class StaticVector {
private:
    T data_;
public:
    StaticVector() = default;
// Culprit
    StaticVector(const StaticVector& v) {
        for (std::size_t k = 0; k < n; ++k) {
            data_ = v.data_;
        }
    }
    StaticVector(StaticVector&& v) {
        for (std::size_t k = 0; k < n; ++k) {
            data_ = std::move(v.data_);
        }
    }
    StaticVector& operator=(const StaticVector& v) {
        for (std::size_t k = 0; k < n; ++k) {
            data_ = v.data_;
        }
        return *this;
    }
    StaticVector& operator=(StaticVector&& v) {
        for (std::size_t k = 0; k < n; ++k) {
            data_ = std::move(v.data_);
        }
        return *this;
    }
// Culprit
    T& operator[](std::size_t k) {
        return data_;
    }
    const T& operator[](std::size_t k) const {
        return data_;
    }
};

StaticVector<double, 2> ode(const StaticVector<double, 2>& y) {
    StaticVector<double, 2> dy_dt;
    dy_dt[0] = cos(y[0]);
    dy_dt[1] = sin(y[1]);

    return dy_dt;
}

 

0 Kudos
3 Replies
velvia
Beginner
635 Views

Hi,

I have managed to make the example much more simple. The following code

class Test {
public:
	Test() = default;
	Test(const Test& x);
};

Test f() {
	auto x = Test( );

	return x;
}

does generate RVO but this one

class Test {
public:
	Test() = default;
};

Test f() {
	auto x = Test( );

	return x;
}

does not and nothing says in the standard that it should not. It makes all std::array<T, n> implementations that I know of miss return value optimization. I believe that this should be filed as an "optimization bug" of the compiler.

0 Kudos
KitturGanesh
Employee
635 Views

Hi Velvia,
This is an interesting issue and looks like the compiler does RVO involving copy constructors (from your first case) but need to find out more on your other case with the developers. I'll update you accordingly, thanks
_Kittur

0 Kudos
Berthoul__Berenger
635 Views

Hi,

I have the exact same problem with icpc 17 with -O3. If the copy constructor is not declared/defined as the compiler should have generated, it can result in a catastrophic degradation of performance (x3 times slower in my moderately complicated case). Any news about this performance issue ?

Bérenger

0 Kudos
Reply