求MSVC环境下std::execution::unseq较seq性能更优的测试示例
MSVC下std::execution::unseq优于seq的测试示例
以下是针对MSVC(C++20、O2优化、AVX2指令集)环境的测试场景,核心是大规模无依赖元素级数值运算——这类场景中std::execution::unseq能明确允许编译器启用激进的SIMD优化,而seq策略可能因保守性限制优化空间。
测试代码
#include <algorithm> #include <execution> #include <vector> #include <chrono> #include <cmath> #include <iostream> int main() { // 生成大规模测试数据(1000万双精度浮点数) const size_t data_size = 10'000'000; std::vector<double> data(data_size); std::generate(std::execution::seq, data.begin(), data.end(), []() { return static_cast<double>(rand()) / RAND_MAX * 1000.0; }); // 测试std::execution::seq auto seq_data = data; auto start_seq = std::chrono::high_resolution_clock::now(); std::transform(std::execution::seq, seq_data.begin(), seq_data.end(), seq_data.begin(), [](double val) { return val * 2.0 + std::sqrt(val); }); auto end_seq = std::chrono::high_resolution_clock::now(); auto duration_seq = std::chrono::duration_cast<std::chrono::milliseconds>(end_seq - start_seq).count(); // 测试std::execution::unseq auto unseq_data = data; auto start_unseq = std::chrono::high_resolution_clock::now(); std::transform(std::execution::unseq, unseq_data.begin(), unseq_data.end(), unseq_data.begin(), [](double val) { return val * 2.0 + std::sqrt(val); }); auto end_unseq = std::chrono::high_resolution_clock::now(); auto duration_unseq = std::chrono::duration_cast<std::chrono::milliseconds>(end_unseq - start_unseq).count(); // 输出结果 std::cout << "seq耗时: " << duration_seq << "ms\n"; std::cout << "unseq耗时: " << duration_unseq << "ms\n"; std::cout << "性能提升: " << static_cast<double>(duration_seq - duration_unseq) / duration_seq * 100 << "%\n"; // 验证结果一致性(确保优化不影响正确性) bool equal = std::equal(seq_data.begin(), seq_data.end(), unseq_data.begin(), [](double a, double b) { return std::abs(a - b) < 1e-6; }); std::cout << "结果一致性: " << (equal ? "符合" : "不符合") << "\n"; return 0; }
编译要求
确保MSVC编译选项设置:
- 语言标准:
/std:c++20 - 优化级别:
/O2 - 指令集:
/arch:AVX2 - 编译模式:Release(禁用调试符号及调试相关的限制优化)
效果说明
在支持AVX2的CPU上,当数据规模足够大时,unseq版本的耗时通常比seq版本低30%-50%。原因在于:
unseq明确告知编译器,循环迭代之间无数据依赖、无顺序要求,编译器可以完全放开SIMD指令生成(比如用AVX2的256位寄存器一次处理4个双精度浮点数)。seq策略下,即使开启O2优化,编译器可能因保守性(比如对循环内操作的依赖判断更严格)无法充分利用SIMD,或者无法做指令重排优化。
注意事项
- 数据规模过小会导致SIMD优化的收益被函数调用、数据加载等开销抵消,建议测试规模不低于100万元素。
- 避免循环内有内存依赖、分支跳转或I/O操作,否则
unseq无法发挥优势。
内容的提问来源于stack exchange,提问作者Joseph Perez
相关产品推荐
相关产品推荐

