Я написал тест для тестирования двух способов изменения и отправки boost :: container :: static_vector в std :: vector. Они выглядят странным образом.
Первый:
typedef boost::container::static_vector<int, 4> Bar;
void foo(Bar& bar, std::vector<Bar>& bars)
{
const auto oldSize = bar.size();
bar.emplace_back(4);
bars.emplace_back(bar);
bar.resize(oldSize);
}
Он изменяет локальную версию, копирует ее в вектор и затем возвращает локальную версию в исходное состояние.
Второй:
typedef boost::container::static_vector<int, 4> Bar;
void foo(Bar& bar, std::vector<Bar>& bars)
{
bars.emplace_back(bar);
bars.back().emplace_back(4);
}
Вместо того, чтобы изменять и возвращать локальную версию, он просто изменяет свою копию прямо на вектор.
Я считаю, что vector::emplace_back
в обеих версиях должны работать одинаково хорошо, так как оба просто копируют объект фиксированного размера. Кроме того, обе реализации foo вызывают static_vector::emplace_back
ровно один раз. resize
кажется довольно дешевым. Он должен сводиться к проверке, является ли oldSize
меньше текущего bar
размера (он всегда есть), и перезаписывать внутреннюю переменную bar
размера. Очевидно, здесь нет деструктора. Второе внедрение вызывает вместо этого vector::back
, который обращается к памяти кучи.
В общем, я ожидал, что обе версии будут одинаково производительными, возможно даже с небольшим преимуществом первой версии (видя, что она обращается к куче памяти только один раз, в отличие от второй). Тем не менее, простой тест показывает совершенно другие результаты.
Benchmark:
std::vector<Bar> bars;
for(int i = 0; i < 100; ++i)
{
bars.clear();
Bar bar = {5, 6, 7};
for(int j = 0; j < 10000000; ++j)
foo(bar, bars);
}
Первый:
real 0m8,044s
user 0m7,846s
sys 0m0,152s
Во-вторых:
real 0m5,754s
user 0m5,559s
sys 0m0,184s
Вопрос в том, откуда взялась эта огромная разница?
Как ни странно, изменение емкости static_vector
, похоже, уменьшает этот разрыв. Э.Г.
typedef boost::container::static_vector<int, 16> Bar;
выравнивает любую разницу во времени. Почему небольшая емкость static_vector
делает так много различий между этими двумя способами, хотя кажется, что эта проблема больше не влияет на более крупные?
Я использую g ++ 8.3.0 с флагами -Ofast -std=c++17 -flto
.
EDIT:
Вот немного более длинный тест с большей static_vector
емкостью (8):
std::vector<Bar> bars;
for(int i = 0; i < 1000; ++i)
{
bars.clear();
Bar bar = {5, 6, 7, 8, 9, 10, 11};
for(int j = 0; j < 10000000; ++j)
foo(bar, bars);
}
1m42,282s
против 1m31,387s
все еще показывает аналогичную разницу. Действительно, первая реализация может сойти с объяснения, что она просто копирует больше байтов. Но тогда возникает вопрос, почему аналогичный тест с увеличением емкости до 16 показывает всего лишь 2m46,733s
против 2m45,128s
. Я ожидаю увидеть ту же разницу в 11 с.