矢量与动态数组基准测试 - 瓶颈是什么?

vector vs dynamic array benchmarks - what is the bottleneck?

鼓励在动态数组上使用 STL,但我很好奇瓶颈是什么? MAX_PACKET_LENGTH32768.

---------------------------------------------------------------------------
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;
    }
}

您正在比较构建 std::vector 的成本与在堆上分配数组的成本。当您创建一个 std::vector 时,它会在内部分配一个堆上的数组,但是会有额外的开销,因为 std::vector 本身是一个需要构造和存储的对象(可能在堆栈上或在堆)。因此,创建 std::vector 的时间应该比创建 new char[].

的时间长

也就是说,BM_RawInitBM_VectorInit 之间还有另一个区别。当你用一个整数参数构造一个 std::vector 时,如 std::vector<char> a(MAX_PACKET_LENGTH) 中,会发生两件事。 Space 将在堆上分配 MAX_PACKET_LENGTH 个项目 这些项目也将被默认构造。另一方面,当您执行 new char[MAX_PACKET_LENGTH] 时,只会发生分配。

为了更好的比较,尝试创建仅分配 space 的第三个基准,如下所示:

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 项分配足够的 space。在实际代码中,这通常可以忽略不计,但为了您的基准,它可以部分解释为什么 BM_VectorReserveBM_RawInit.

花费更长的时间

首先,正如@juanchopanza 所建议的那样——如果您不提供适当的测试程序,我们将无法复制您的图形;你刚刚给了我们两个函数,它们什么都不做,也不会在二进制文件中产生任何结果。

无论如何,开销似乎是由于 std::vectorchar 值进行了零初始化。

如果您想避免这种情况发生,或者只是为了公平地进行基准测试,请使用 a struct which wraps a char and doesn't initialize it 作为矢量元素类型,然后再次 运行 您的测试。不过,我不建议在生产代码中实际使用这种愚蠢的结构——使用您实际需要的类型。

说到使用你需要的东西——完全可以使用:

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

然后也许:

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

而且几乎所有可以使用 std::vector 的地方都可以使用 。 (不过请注意,std::span 仅在 C++20 中出现,现在您需要 GSL 实现)。