#include #include #include #include #include #include #include #include // 修正include路径 #include "simd_api.h" #include "aligned_allocator.h" #include "performance_timer.h" using namespace shm_test; namespace { // ============================================================================ // 测试数据生成辅助函数 // ============================================================================ /** * @brief 生成正弦波测试数据 * @param frequency 频率(0-1,相对于采样率) * @param num_samples 样本数量 * @return 正弦波数据向量 */ template> std::vector generate_sine_wave(float frequency, size_t num_samples) { std::vector data(num_samples); for (size_t i = 0; i < num_samples; ++i) { data[i] = std::sin(2.0f * 3.14159265f * frequency * i); } return data; } /** * @brief 生成常数值测试数据 * @param value 常数值 * @param num_samples 样本数量 * @return 常数值数据向量 */ template> std::vector generate_constant_data(float value, size_t num_samples) { return std::vector(num_samples, value); } /** * @brief 检查两个浮点数是否接近 * @param a 第一个值 * @param b 第二个值 * @param tolerance 容差 * @return 是否接近 */ bool float_near(float a, float b, float tolerance = 1e-5f) { if (std::isnan(a) || std::isnan(b)) return false; if (std::isinf(a) || std::isinf(b)) return a == b; return std::abs(a - b) < tolerance; } /** * @brief 检查两个缓冲区是否相等(允许浮点误差) * @param expected 期望值 * @param actual 实际值 * @param tolerance 容差 * @return 是否相等 */ template bool buffers_equal(const std::vector& expected, const std::vector& actual, float tolerance = 1e-5f) { if (expected.size() != actual.size()) { return false; } for (size_t i = 0; i < expected.size(); ++i) { if (!float_near(expected[i], actual[i], tolerance)) { return false; } } return true; } // ============================================================================ // 功能单元测试 - 参数化测试 // ============================================================================ /** * @brief 测试参数结构体 */ struct AudioProcessingTestParams { size_t buffer_size; // 缓冲区大小 int num_channels; // 通道数 float gain_value; // 增益值 }; /** * @brief 填充缓冲区功能测试类 */ class FillBufferTest : public ::testing::TestWithParam { protected: void SetUp() override { params = GetParam(); } AudioProcessingTestParams params; }; TEST_P(FillBufferTest, FillsBufferWithValue) { const float fill_value = 3.14f; size_t total_samples = params.buffer_size * params.num_channels; std::vector buffer(total_samples); simd::fill_buffer(buffer.data(), fill_value, total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(buffer[i], fill_value) << "值不匹配于索引 " << i; } } TEST_P(FillBufferTest, FillWithZero) { size_t total_samples = params.buffer_size * params.num_channels; std::vector buffer(total_samples); simd::fill_buffer(buffer.data(), 0.0f, total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_EQ(buffer[i], 0.0f); } } TEST_P(FillBufferTest, FillWithNegativeValue) { const float fill_value = -2.5f; size_t total_samples = params.buffer_size * params.num_channels; std::vector buffer(total_samples); simd::fill_buffer(buffer.data(), fill_value, total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(buffer[i], fill_value); } } INSTANTIATE_TEST_SUITE_P( FillBufferParametrized, FillBufferTest, ::testing::Values( AudioProcessingTestParams{64, 1, 1.0f}, AudioProcessingTestParams{256, 2, 1.0f}, AudioProcessingTestParams{1024, 4, 1.0f}, AudioProcessingTestParams{4096, 8, 1.0f}, AudioProcessingTestParams{8192, 1, 1.0f} ) ); /** * @brief 应用增益功能测试类 */ class ApplyGainTest : public ::testing::TestWithParam { protected: void SetUp() override { params = GetParam(); } AudioProcessingTestParams params; }; TEST_P(ApplyGainTest, AppliesGainCorrectly) { size_t total_samples = params.buffer_size * params.num_channels; const float gain = params.gain_value; std::vector src(total_samples, 2.0f); std::vector dst(total_samples, 0.0f); simd::apply_gain(src.data(), dst.data(), gain, total_samples); const float expected_value = 2.0f * gain; for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(dst[i], expected_value) << "增益应用错误于索引 " << i; } } TEST_P(ApplyGainTest, GainZeroMakesOutputZero) { size_t total_samples = params.buffer_size * params.num_channels; std::vector src(total_samples, 5.0f); std::vector dst(total_samples, 1.0f); simd::apply_gain(src.data(), dst.data(), 0.0f, total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(dst[i], 0.0f); } } TEST_P(ApplyGainTest, GainOnePreservesValues) { size_t total_samples = params.buffer_size * params.num_channels; auto raw_src = generate_sine_wave(0.1f, total_samples); std::vector src(raw_src.begin(), raw_src.end()); std::vector dst(total_samples, 0.0f); simd::apply_gain(src.data(), dst.data(), 1.0f, total_samples); // 验证增益为1.0时,源数据应该保持不变 for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(src[i], raw_src[i]); } } TEST_P(ApplyGainTest, NegativeGainInvertsSignal) { size_t total_samples = params.buffer_size * params.num_channels; std::vector src(total_samples, 3.0f); std::vector dst(total_samples, 0.0f); simd::apply_gain(src.data(), dst.data(), -1.0f, total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(dst[i], -3.0f); } } INSTANTIATE_TEST_SUITE_P( ApplyGainParametrized, ApplyGainTest, ::testing::Values( AudioProcessingTestParams{64, 1, 0.0f}, AudioProcessingTestParams{256, 2, 0.5f}, AudioProcessingTestParams{1024, 4, 1.0f}, AudioProcessingTestParams{4096, 8, 2.0f}, AudioProcessingTestParams{8192, 1, 0.1f} ) ); /** * @brief 混音功能测试类 */ class MixAudioTest : public ::testing::TestWithParam { protected: void SetUp() override { params = GetParam(); } AudioProcessingTestParams params; }; TEST_P(MixAudioTest, MixesAudioCorrectly) { size_t total_samples = params.buffer_size * params.num_channels; std::vector src1(total_samples, 1.0f); std::vector src2(total_samples, 2.0f); std::vector dst(total_samples, 0.0f); simd::mix_audio(src1.data(), src2.data(), dst.data(), total_samples); for (size_t i = 0; i < total_samples; ++i) { EXPECT_FLOAT_EQ(dst[i], 3.0f) << "混音结果错误于索引 " << i; } } TEST_P(MixAudioTest, MixWithZero) { size_t total_samples = params.buffer_size * params.num_channels; std::vector src1 = generate_sine_wave(0.1f, total_samples); std::vector src2(total_samples, 0.0f); std::vector dst(total_samples, 0.0f); simd::mix_audio(src1.data(), src2.data(), dst.data(), total_samples); EXPECT_TRUE(buffers_equal(src1, dst, 1e-5f)); } TEST_P(MixAudioTest, MixSymmetry) { size_t total_samples = params.buffer_size * params.num_channels; std::vector src1 = generate_sine_wave(0.1f, total_samples); std::vector src2 = generate_sine_wave(0.05f, total_samples); std::vector dst1(total_samples, 0.0f); std::vector dst2(total_samples, 0.0f); simd::mix_audio(src1.data(), src2.data(), dst1.data(), total_samples); simd::mix_audio(src2.data(), src1.data(), dst2.data(), total_samples); EXPECT_TRUE(buffers_equal(dst1, dst2, 1e-5f)); } INSTANTIATE_TEST_SUITE_P( MixAudioParametrized, MixAudioTest, ::testing::Values( AudioProcessingTestParams{64, 1, 0.0f}, AudioProcessingTestParams{256, 2, 0.0f}, AudioProcessingTestParams{1024, 4, 0.0f}, AudioProcessingTestParams{4096, 8, 0.0f}, AudioProcessingTestParams{8192, 1, 0.0f} ) ); // ============================================================================ // 边界条件测试 // ============================================================================ class BoundaryConditionTest : public ::testing::Test { protected: const float epsilon = 1e-5f; }; TEST_F(BoundaryConditionTest, FillBufferZeroLength) { std::vector buffer(10, 1.0f); simd::fill_buffer(buffer.data(), 0.0f, 0); // 不应该修改任何元素 for (auto val : buffer) { EXPECT_EQ(val, 1.0f); } } TEST_F(BoundaryConditionTest, FillBufferSingleSample) { std::vector buffer(1); const float fill_value = 7.5f; simd::fill_buffer(buffer.data(), fill_value, 1); EXPECT_FLOAT_EQ(buffer[0], fill_value); } TEST_F(BoundaryConditionTest, ApplyGainZeroLength) { std::vector src(10, 5.0f); std::vector dst(10, 1.0f); simd::apply_gain(src.data(), dst.data(), 2.0f, 0); for (auto val : dst) { EXPECT_EQ(val, 1.0f); } } TEST_F(BoundaryConditionTest, ApplyGainSingleSample) { std::vector src = {3.0f}; std::vector dst = {0.0f}; simd::apply_gain(src.data(), dst.data(), 4.0f, 1); EXPECT_FLOAT_EQ(dst[0], 12.0f); } TEST_F(BoundaryConditionTest, MixAudioZeroLength) { std::vector src1(10, 1.0f); std::vector src2(10, 2.0f); std::vector dst(10, 0.0f); simd::mix_audio(src1.data(), src2.data(), dst.data(), 0); for (auto val : dst) { EXPECT_EQ(val, 0.0f); } } TEST_F(BoundaryConditionTest, MixAudioSingleSample) { std::vector src1 = {2.5f}; std::vector src2 = {3.5f}; std::vector dst = {0.0f}; simd::mix_audio(src1.data(), src2.data(), dst.data(), 1); EXPECT_FLOAT_EQ(dst[0], 6.0f); } TEST_F(BoundaryConditionTest, ExtremeLargeValues) { std::vector buffer(100); const float large_value = 1e6f; simd::fill_buffer(buffer.data(), large_value, buffer.size()); for (auto val : buffer) { EXPECT_FLOAT_EQ(val, large_value); } } TEST_F(BoundaryConditionTest, ExtremeSmallValues) { std::vector buffer(100); const float small_value = 1e-6f; simd::fill_buffer(buffer.data(), small_value, buffer.size()); for (auto val : buffer) { EXPECT_NEAR(val, small_value, 1e-12f); } } TEST_F(BoundaryConditionTest, FillBufferWithMaxFloat) { std::vector buffer(10); const float max_val = std::numeric_limits::max(); simd::fill_buffer(buffer.data(), max_val, buffer.size()); for (auto val : buffer) { EXPECT_EQ(val, max_val); } } TEST_F(BoundaryConditionTest, ApplyGainWithVerySmallGain) { std::vector src(100, 1e6f); std::vector dst(100); const float tiny_gain = 1e-7f; simd::apply_gain(src.data(), dst.data(), tiny_gain, src.size()); for (size_t i = 0; i < src.size(); ++i) { EXPECT_NEAR(dst[i], src[i] * tiny_gain, 1e-10f); } } // ============================================================================ // 数据对齐测试 // ============================================================================ class AlignmentTest : public ::testing::Test { protected: template bool check_alignment(const void* ptr) const { return reinterpret_cast(ptr) % Alignment == 0; } }; TEST_F(AlignmentTest, SSEAlignedBuffer) { std::vector> buffer(1024); EXPECT_TRUE(check_alignment(buffer.data())); } TEST_F(AlignmentTest, AVXAlignedBuffer) { std::vector> buffer(1024); EXPECT_TRUE(check_alignment(buffer.data())); } TEST_F(AlignmentTest, AVX512AlignedBuffer) { std::vector> buffer(1024); EXPECT_TRUE(check_alignment(buffer.data())); } TEST_F(AlignmentTest, FillBufferMaintainsAlignment) { std::vector buffer(1024); EXPECT_TRUE(check_alignment(buffer.data())); simd::fill_buffer(buffer.data(), 1.0f, buffer.size()); // 数据仍然在原地,对齐不变 EXPECT_TRUE(check_alignment(buffer.data())); } TEST_F(AlignmentTest, ApplyGainWithAlignedData) { std::vector src(256); std::vector dst(256); EXPECT_TRUE(check_alignment(src.data())); EXPECT_TRUE(check_alignment(dst.data())); simd::apply_gain(src.data(), dst.data(), 0.5f, src.size()); // 对齐在操作后仍然有效 EXPECT_TRUE(check_alignment(src.data())); EXPECT_TRUE(check_alignment(dst.data())); } TEST_F(AlignmentTest, MixAudioWithAlignedData) { std::vector src1(512); std::vector src2(512); std::vector dst(512); EXPECT_TRUE(check_alignment(src1.data())); EXPECT_TRUE(check_alignment(src2.data())); EXPECT_TRUE(check_alignment(dst.data())); simd::mix_audio(src1.data(), src2.data(), dst.data(), src1.size()); EXPECT_TRUE(check_alignment(dst.data())); } TEST_F(AlignmentTest, UnalignedBufferHandling) { // 创建一个未对齐的缓冲区(通过跳过第一个字节) std::vector aligned_storage(1025); float* unaligned_ptr = aligned_storage.data() + 1; // 偏移1个元素,破坏对齐 // 虽然指针未对齐,但函数应该仍然能工作(可能性能较低) // 这测试了函数的鲁棒性,而不是对齐的要求 std::vector expected(1024, 5.0f); simd::fill_buffer(unaligned_ptr, 5.0f, 1024); for (size_t i = 0; i < 1024; ++i) { EXPECT_FLOAT_EQ(unaligned_ptr[i], 5.0f); } } // ============================================================================ // 性能基准测试 // ============================================================================ class PerformanceBenchmark : public ::testing::Test { protected: const int ITERATIONS = 100; }; TEST_F(PerformanceBenchmark, FillBufferThroughput64Samples) { std::vector buffer(64); LatencyRecorder latency_recorder("FillBuffer_64"); for (int iter = 0; iter < ITERATIONS; ++iter) { ScopedTimer timer("", false); simd::fill_buffer(buffer.data(), 1.0f, buffer.size()); timer.stop(); latency_recorder.record(timer.elapsed_ns()); } auto stats = latency_recorder.get_statistics(); double samples_per_sec = (64.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS); std::cout << "FillBuffer (64 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl; EXPECT_GT(samples_per_sec, 0.0); // 基本健全性检查 } TEST_F(PerformanceBenchmark, FillBufferThroughput1024Samples) { std::vector buffer(1024); LatencyRecorder latency_recorder("FillBuffer_1024"); for (int iter = 0; iter < ITERATIONS; ++iter) { ScopedTimer timer("", false); simd::fill_buffer(buffer.data(), 1.0f, buffer.size()); timer.stop(); latency_recorder.record(timer.elapsed_ns()); } auto stats = latency_recorder.get_statistics(); double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS); std::cout << "FillBuffer (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl; EXPECT_GT(samples_per_sec, 0.0); } TEST_F(PerformanceBenchmark, ApplyGainThroughput) { std::vector src(1024, 1.0f); std::vector dst(1024); LatencyRecorder latency_recorder("ApplyGain_1024"); for (int iter = 0; iter < ITERATIONS; ++iter) { ScopedTimer timer("", false); simd::apply_gain(src.data(), dst.data(), 0.5f, src.size()); timer.stop(); latency_recorder.record(timer.elapsed_ns()); } auto stats = latency_recorder.get_statistics(); double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS); std::cout << "ApplyGain (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl; EXPECT_GT(samples_per_sec, 0.0); } TEST_F(PerformanceBenchmark, MixAudioThroughput) { std::vector src1(1024, 1.0f); std::vector src2(1024, 2.0f); std::vector dst(1024); LatencyRecorder latency_recorder("MixAudio_1024"); for (int iter = 0; iter < ITERATIONS; ++iter) { ScopedTimer timer("", false); simd::mix_audio(src1.data(), src2.data(), dst.data(), src1.size()); timer.stop(); latency_recorder.record(timer.elapsed_ns()); } auto stats = latency_recorder.get_statistics(); double samples_per_sec = (1024.0 * ITERATIONS * 1e9) / (stats.avg() * ITERATIONS); std::cout << "MixAudio (1024 samples): " << samples_per_sec / 1e6 << " MSamples/sec" << std::endl; EXPECT_GT(samples_per_sec, 0.0); } // ============================================================================ // 跨实现一致性测试 // ============================================================================ class CrossImplementationConsistencyTest : public ::testing::Test { protected: void SetUp() override { // 初始化测试数据 test_data_ = generate_sine_wave(0.1f, 1024); expected_result_ = test_data_; } std::vector test_data_; std::vector expected_result_; }; TEST_F(CrossImplementationConsistencyTest, FillBufferConsistency) { std::vector result(1024); // 使用SIMD实现 simd::fill_buffer(result.data(), 5.0f, 1024); // 验证所有元素都是5.0 for (size_t i = 0; i < 1024; ++i) { EXPECT_FLOAT_EQ(result[i], 5.0f) << "SIMD实现结果不一致于索引 " << i; } } TEST_F(CrossImplementationConsistencyTest, ApplyGainConsistency) { std::vector src(1024, 3.0f); std::vector result(1024); // 使用SIMD实现 simd::apply_gain(src.data(), result.data(), 2.0f, 1024); // 验证结果为6.0(3.0 * 2.0) for (size_t i = 0; i < 1024; ++i) { EXPECT_FLOAT_EQ(result[i], 6.0f) << "SIMD实现结果不一致于索引 " << i; } } TEST_F(CrossImplementationConsistencyTest, MixAudioConsistency) { std::vector src1(1024, 1.0f); std::vector src2(1024, 2.0f); std::vector result(1024); // 使用SIMD实现 simd::mix_audio(src1.data(), src2.data(), result.data(), 1024); // 验证结果为3.0(1.0 + 2.0) for (size_t i = 0; i < 1024; ++i) { EXPECT_FLOAT_EQ(result[i], 3.0f) << "SIMD实现结果不一致于索引 " << i; } } // ============================================================================ // 额外功能测试 // ============================================================================ /** * @brief 计算RMS值的辅助函数 */ float calculate_rms(const std::vector& data) { double sum = 0.0; for (float val : data) { sum += val * val; } return std::sqrt(sum / data.size()); } /** * @brief 计算峰值辅助函数 */ float calculate_peak(const std::vector& data) { float peak = 0.0f; for (float val : data) { peak = std::max(peak, std::abs(val)); } return peak; } class AdditionalFunctionalityTest : public ::testing::Test { protected: void SetUp() override { test_data_ = generate_sine_wave(0.1f, 1024); } std::vector test_data_; }; TEST_F(AdditionalFunctionalityTest, RMSCalculation) { std::vector src(test_data_.begin(), test_data_.end()); std::vector dst(1024); // 使用SIMD实现计算RMS float rms = simd::calculate_rms(src.data(), 1024); // 验证RMS值在合理范围内 EXPECT_GT(rms, 0.0); EXPECT_LT(rms, 1.0); // 验证与参考实现的一致性 std::vector test_data_copy(test_data_.begin(), test_data_.end()); float expected_rms = calculate_rms(test_data_copy); EXPECT_NEAR(rms, expected_rms, 0.01f); } TEST_F(AdditionalFunctionalityTest, PeakCalculation) { std::vector src(test_data_.begin(), test_data_.end()); // 使用SIMD实现计算峰值 float peak = simd::calculate_peak(src.data(), 1024); // 验证峰值在合理范围内 EXPECT_GT(peak, 0.0); EXPECT_LT(peak, 1.1f); // 允许一些误差 // 验证与参考实现的一致性 std::vector test_data_copy(test_data_.begin(), test_data_.end()); float expected_peak = calculate_peak(test_data_copy); EXPECT_NEAR(peak, expected_peak, 0.01f); } TEST_F(AdditionalFunctionalityTest, StereoToMono) { // 创建交错的立体声测试数据 (LRLRLR...) std::vector stereo_interleaved(1024); std::vector mono_result(512); // 填充交错数据:左声道=1.0,右声道=2.0 for (size_t i = 0; i < 512; ++i) { stereo_interleaved[i * 2] = 1.0f; // 左声道 stereo_interleaved[i * 2 + 1] = 2.0f; // 右声道 } // 转换为单声道 simd::stereo_to_mono(stereo_interleaved.data(), mono_result.data(), 512); // 验证结果为平均值 (1.0 + 2.0) / 2 = 1.5 for (size_t i = 0; i < 512; ++i) { EXPECT_FLOAT_EQ(mono_result[i], 1.5f); } } } // namespace