提升分配器性能

问题描述

我试图通过使用 boost::container::allocators 来提高性能

创建a simple experiment

#include <chrono>
#include <set>
#include <vector>
#include <iostream>

#include <boost/container/pmr/vector.hpp>
#include <boost/container/pmr/set.hpp>
#include <boost/container/allocator.hpp>
#include <boost/container/node_allocator.hpp>
#include <boost/container/adaptive_pool.hpp>

template<typename Vector>
void pushBackTest(bool makeReserve)
{
    Vector v;

    const std::size_t count = 10000000;
    if (makeReserve)
    {
        v.reserve(count);
    }
    auto start = std::chrono::high_resolution_clock::Now();

    for (std::size_t i = 0 ; i < count ; ++i)
    {
        v.push_back(typename Vector::value_type{});
    }

    auto end = std::chrono::high_resolution_clock::Now();

    const std::chrono::duration<double> duration = end - start;
    std::cout << duration.count() << std::endl;
}

template<typename Set>
void setInserttest()
{
    Set v;

    const std::size_t count = 1000000;

    auto start = std::chrono::high_resolution_clock::Now();

    for (std::size_t i = 0 ; i < count ; ++i)
    {
        v.insert(std::rand());
    }

    auto end = std::chrono::high_resolution_clock::Now();

    const std::chrono::duration<double> duration = end - start;
    std::cout << duration.count() << std::endl;
}

int main()
{
    std::srand((unsigned)std::time(nullptr));

    std::cout << "Vector" << std::endl;
    std::cout << "No reserve" << std::endl;
    pushBackTest<std::vector<int>>(false);
    pushBackTest<std::vector<int,boost::container::allocator<int>>>(false);
    pushBackTest<boost::container::vector<int,boost::container::allocator<int>>>(false);
    pushBackTest<boost::container::pmr::vector<int>>(false);

    std::cout << "Reserve" << std::endl;
    pushBackTest<std::vector<int>>(true);
    pushBackTest<std::vector<int,boost::container::allocator<int>>>(true);
    pushBackTest<boost::container::vector<int,boost::container::allocator<int>>>(true);
    pushBackTest<boost::container::pmr::vector<int>>(true);

    std::cout << "Set" << std::endl;
    setInsertTest<std::set<int>>();
    setInsertTest<std::set<int,std::less<int>,boost::container::node_allocator<int>>>();
    setInsertTest<std::set<int,boost::container::adaptive_pool<int>>>();
    setInsertTest<boost::container::set<int>>();
    setInsertTest<boost::container::set<int,boost::container::node_allocator<int>>>();
    setInsertTest<boost::container::set<int,boost::container::adaptive_pool<int>>>();
    setInsertTest<boost::container::pmr::set<int>>();
    
    return 0;
}

使用 clang++12 prog.cc -Wall -Wextra -O2 -march=native -I/Opt/wandBox/boost-1.73.0/clang-head/include -std=c++14 编译

结果:

Vector
No reserve
0.10387
0.095851
0.104992
0.0982694
0.102469
Reserve
0.0372922
0.0489831
0.0518053
0.052593
0.0680981
Set
0.760118
0.7739
0.769929
1.09121
0.685224
0.747359
1.18725

据我所知,分配器并没有带来任何性能提升。
任何人都可以看看并告诉我我做错了什么吗?

解决方法

据我所知,分配器没有带来任何性能提升。

在您的特定基准测试中,无论您使用什么分配器,在执行 vector<>::reserve 之前调用 vector<>::push_back 都会产生最大的性能提升。

当您不调用 vector<>::reserve 时,基准测试会在向量增长时分配更大的内存块,而这种情况并不是分配器针对的优化。现代分配器通常针对不同线程使用时的最小锁争用、更少的内存碎片、更好的缓存利用率进行了优化,您的基准测试无法从/观察和衡量这些方面受益。


setInsertTest 中插入 std::rand 调用的结果。这个伪随机数生成器必须通过调用 std::srand(0) 重置,以便每个基准使用完全相同的伪随机数序列,否则它会测量不同容器在来自同一分布的不相交样本上的性能。>


您可能喜欢使用 Google Benchmark,因为它可以自动化

  • 时间,
  • 报告,
  • 禁用基准代码省略,
  • 可以报告集中趋势(均值和中位数)和离散度(标准差)的统计量度

无需为此编写一行代码。