Boost MultiArrays性能较差
Boost MultiArrays performance is poor
我注意到我的boost多数组与STL Vector相比表现非常糟糕。我遇到了之前问过的这个问题,其中最受欢迎的答案是
1) Boost几乎和原生数组
一样快2)您需要改变访问数据元素的顺序,以获得Boost MultiArray的最佳性能。另外,你需要在发布模式下运行,而不是调试模式。
好吧,我做了所有这些,但是我的MultiArrays的性能相当差。
我在这里张贴我的代码:
A) WITH DEFAULT ORDERING
#include <windows.h>
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_DISABLE_ASSERTS
#include <boost/multi_array.hpp>
#include <stdio.h>
#include <conio.h>
#include <iostream>
int main(int argc, char* argv[])
{
const int X_SIZE = 400;
const int Y_SIZE = 400;
const int ITERATIONS = 500;
unsigned int startTime = 0;
unsigned int endTime = 0;
// Create the boost array
typedef boost::multi_array<double, 2> ImageArrayType;
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
// Create the native array
double *nativeMatrix = new double [X_SIZE * Y_SIZE];
//------------------Measure boost----------------------------------------------
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int y = 0; y < Y_SIZE; ++y)
{
for (int x = 0; x < X_SIZE; ++x)
{
boostMatrix[x][y] *= 2.345;
}
}
}
endTime = ::GetTickCount();
printf("[Boost] Elapsed time: %6.3f secondsn", (endTime - startTime) / 1000.0);
//------------------Measure native-----------------------------------------------
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int y = 0; y < Y_SIZE; ++y)
{
for (int x = 0; x < X_SIZE; ++x)
{
nativeMatrix[x + (y * X_SIZE)] *= 2.345;
}
}
}
endTime = ::GetTickCount();
printf("[Native]Elapsed time: %6.3f secondsn", (endTime - startTime) / 1000.0);
return 0;
}
B) WITH倒序
#include <windows.h>
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_DISABLE_ASSERTS
#include <boost/multi_array.hpp>
#include <stdio.h>
#include <conio.h>
#include <iostream>
int main(int argc, char* argv[])
{
const int X_SIZE = 400;
const int Y_SIZE = 400;
const int ITERATIONS = 500;
unsigned int startTime = 0;
unsigned int endTime = 0;
// Create the boost array
typedef boost::multi_array<double, 2> ImageArrayType;
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
// Create the native array
double *nativeMatrix = new double [X_SIZE * Y_SIZE];
//------------------Measure boost----------------------------------------------
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
boostMatrix[x][y] *= 2.345;
}
}
}
endTime = ::GetTickCount();
printf("[Boost] Elapsed time: %6.3f secondsn", (endTime - startTime) / 1000.0);
//------------------Measure native-----------------------------------------------
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
nativeMatrix[x + (y * X_SIZE)] *= 2.345;
}
}
}
endTime = ::GetTickCount();
printf("[Native]Elapsed time: %6.3f secondsn", (endTime - startTime) / 1000.0);
return 0;
}
在每一种可能的排列中,我的基准测试都大致相同:
1)本机代码:0.15s
2) For Boost MultiArray: 1.0s
我使用的是Visual Studio 2010。
我的问题是:鉴于我正在使用Visual Studio,如何从Boost MultiArrays获得良好的性能?
更新:我切换到Visual Studio 2013。在这里,我启用了Qvec-report2编译器开关。非常有趣的是,当我编译的时候,我开始收到一条信息说编译器无法向量化。下面是一个示例信息消息,它看起来几乎像一个警告。对于最简单的代码,我收到了好几条这样的消息。
——解析函数:void __cdecl ' vector构造器迭代器'(void * __ptr64,unsigned __int64,int,void * __ptr64 (__cdecl*)(void * __ptr64))1> D:WorkspacetestScrapScrapSource.cpp: info C5002:由于原因'1301',循环未矢量化
我认为这是一个主要的线索,为什么Boost多数组在我的Visual Studio上执行较慢,而它们在GCC上执行得很好。有了这些额外的信息,你能想出一个解决问题的方法吗?
@管理员:请把我的问题标记为以前回答过的。
让我们看看现在是否可以解决这个问题。
在这里,我把你的基准测试翻译成谷歌基准测试框架,我发现,如果代码是用适当的优化水平编译的,没有经验理由期望MultiArray会比本机数组慢。我增加了数组的大小,以获得更少的噪声结果。
你必须非常小心你如何测量时间和你真正测量的是什么:
主要问题是,要进行一对一的比较,您需要查看数据在访问之前是如何初始化的。new[]
和boost::multi_array
的主要区别在于,后者在分配后将元素初始化为零。当这种情况发生时,记忆是"热的";(显然支持Boost.MA)
为了使测试更加对称,我使用new[]{}
初始化(也可以使用Google Benchmark)。
这些是结果,(注意"Inverted"表示正确的、有利的访问顺序):
2022-06-12T14:52:44-07:00
Running ./element_access.cppx
Run on (12 X 4600 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x6)
L1 Instruction 32 KiB (x6)
L2 Unified 256 KiB (x6)
L3 Unified 12288 KiB (x1)
Load Average: 4.25, 4.07, 4.38
-------------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------------
MeasureNative 8535616 ns 8535519 ns 83
MeasureBoostMultiArray 91876643 ns 91874361 ns 8
MeasureBoostMultiArrayInverted 8597615 ns 8597571 ns 82
MeasureBoostMultiArrayRaw 8555218 ns 8554977 ns 83
这里是完整的代码,它是用c++ -std=c++17 -O3 -DNDEBUG -DBOOST_DISABLE_ASSERTS element_access.cpp -o element_access.cppx -lbenchmark
编译的。
#include <boost/multi_array.hpp>
#include <benchmark/benchmark.h> // Google micro benchmarking library
const int X_SIZE = 4000;
const int Y_SIZE = 4000;
typedef boost::multi_array<double, 2> ImageArrayType;
static void MeasureNative(benchmark::State& state) {
// Create the native array
double *nativeMatrix = new double [X_SIZE * Y_SIZE]{};
for (auto _ : state) {
for (int y = 0; y < Y_SIZE; ++y)
{
for (int x = 0; x < X_SIZE; ++x)
{
nativeMatrix[x + (y * X_SIZE)] *= 2.345;
}
}
benchmark::DoNotOptimize(nativeMatrix);
}
delete[] nativeMatrix;
}
BENCHMARK(MeasureNative);
static void MeasureBoostMultiArray(benchmark::State& state) {
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
for (auto _ : state) {
for (int y = 0; y < Y_SIZE; ++y)
{
for (int x = 0; x < X_SIZE; ++x)
{
boostMatrix[x][y] *= 2.345;
}
}
benchmark::DoNotOptimize(boostMatrix);
}
}
BENCHMARK(MeasureBoostMultiArray);
static void MeasureBoostMultiArrayInverted(benchmark::State& state) {
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
for (auto _ : state) {
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
boostMatrix[x][y] *= 2.345;
}
}
benchmark::DoNotOptimize(boostMatrix);
}
}
BENCHMARK(MeasureBoostMultiArrayInverted);
static void MeasureBoostMultiArrayRaw(benchmark::State& state) {
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
for (auto _ : state) {
for (int n = 0; n < boostMatrix.num_elements(); ++n)
{
boostMatrix.data()[n] *= 2.345;
}
benchmark::DoNotOptimize(boostMatrix);
}
}
BENCHMARK(MeasureBoostMultiArrayRaw);
BENCHMARK_MAIN();
最后,你可以看到Native, Boost。MultiArray和另一个"MultiArray";将循环转换为相同的机器码:https://godbolt.org/z/bnW9q3Yhe .
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 哪种方法更好,性能明智
- C++ 特征库:引用的性能开销<>
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- 基于范围的 for 循环range_declaration中各种说明符之间的性能差异
- std::p mr::memory_resource 如何与 std::container 产生性能差异?
- Boost MultiArrays性能较差