вектор по сравнению с тестами динамического массива - что является узким местом? - PullRequest
0 голосов
/ 16 мая 2018

Рекомендуется использовать STL над динамическими массивами, но мне интересно, что может быть узким местом?MAX_PACKET_LENGTH - 32768.

---------------------------------------------------------------------------
Benchmark                                    Time           CPU Iterations
---------------------------------------------------------------------------
BM_VectorInit                             1335 ns       1193 ns     497778
BM_RawInit                                  58 ns         55 ns   10000000


static void BM_VectorInit(benchmark::State &state)
{
    for (auto _ : state) 
    {
        std::vector<char> a(MAX_PACKET_LENGTH);
    }
}

static void BM_RawInit(benchmark::State &state)
{
    for (auto _ : state) 
    {
        auto a = new char[MAX_PACKET_LENGTH];
        delete[] a;
    }
}

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Во-первых, как подсказывает @juanchopanza - мы не сможем воспроизвести ваши цифры, если вы не предоставите надлежащую тестовую программу; Вы только что дали нам две функции, которые ничего не делают и ничего не приведут в двоичном виде.

В любом случае, похоже, что издержки связаны с std::vector инициализацией нуля значений char.

Если вы хотите избежать этого или просто выровнять игровое поле для бенчмаркинга, используйте структуру, которая оборачивает символ и не инициализирует его в качестве типа векторного элемента, и запустите свои тесты снова. Я бы не советовал использовать такую ​​глупую структуру в производственном коде - используйте типы, которые вам действительно нужны.

И если говорить об использовании того, что вам нужно - это совершенно нормально использовать:

auto buffer_ptr = std::make_unique<char[]>(MAX_PACKET_LENGTH);

, а затем возможно:

auto buffer = std::span<char>(raw_buffer.get(), MAX_PACKET_LENGTH);

и вы можете использовать span почти везде, где вы можете использовать std::vector s. (Тем не менее, обратите внимание, что std::span появится только в C ++ 20, и сейчас вам потребуется реализация GSL).

0 голосов
/ 16 мая 2018

Вы сравниваете стоимость построения std::vector со стоимостью размещения массива в куче. Когда вы создаете std::vector, он внутренне выделяет массив в куче, но есть дополнительные издержки, поскольку std::vector сам по себе является объектом, который должен быть создан и сохранен (возможно, в стеке или в куче). Следовательно, создание std::vector должно занять больше времени, чем создание new char[].

Как говорится, есть еще одна разница между BM_RawInit и BM_VectorInit. Когда вы создаете std::vector с одним целочисленным аргументом, как в std::vector<char> a(MAX_PACKET_LENGTH), происходят две вещи. В куче будет выделено место для MAX_PACKET_LENGTH предметов и , эти предметы также будут созданы по умолчанию. С другой стороны, когда вы делаете new char[MAX_PACKET_LENGTH], происходит только распределение.

Для лучшего сравнения попробуйте создать третий бенчмарк, который выделяет только пространство, например:

static void BM_VectorReserve(benchmark::State &state)
{
    for (auto _ : state) 
    {
        std::vector<char> a;
        a.reserve(MAX_PACKET_LENGTH);
    }
}

Это не идеальное сравнение, потому что небольшой объем памяти будет выделен в первой строке, где мы объявляем a, а затем, когда мы вызываем reserve, эта начальная память будет освобождена. После этого std::vector выделит достаточно места для MAX_PACKET_LENGTH элементов. В реальном коде это часто незначительно, но ради вашего теста это частично объясняет, почему BM_VectorReserve занимает больше времени, чем BM_RawInit.

...