Your question title specifies 'performance'.
auto is a compile time construct that allows itself to be substituted with a deduced type. Its use doesn't result in different machine instructions, than if you have hand-written the typename it deduced.
The problem is that, in managing performance, type specification and casting is often crucial, and auto can hide that leading programmers to say something different than they intended:
std::vector<std::array<BigStruct, 10000>>& f();
auto va = f(); // copy
for (auto v: va) { // copies
// ...
}
if the programmer had written:
std::vector<std::array<BigStruct, 10000>> va = f();
or
for (std::array<BigStruct, 10000> v : va)
they would have recognized they were specifying by-value. But std::array<BigStruct, 10000> is what auto deduces here and in these cases that translates to by-value.
People drop their guard and forget that auto deduces the type, it doesn't include the ref qualification.
auto& va = f(); // reference
for (auto& v : va) { // references
There was a performance affect here, but it wasn't caused by auto it was a side-effect of (accidentally) explicitly specifying a copy.
auto doesn't mean the same as this it means an instance of this.
auto va = f(); // an instance-of what f returns, thus a copy.
auto& va = f(); // a reference to an instance-of, thus by reference.