Skip to content

Commit a1da249

Browse files
authored
Merge pull request #795 from jdemel/add-rotator-gtest
Add gtest suite for volk_32fc_s32fc_x2_rotator2_32fc
2 parents f9d2ed6 + b125302 commit a1da249

File tree

3 files changed

+228
-5
lines changed

3 files changed

+228
-5
lines changed

lib/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,7 @@ endif()
563563
target_compile_features(volk_obj PUBLIC c_std_17)
564564

565565
#Configure object target properties
566-
if(NOT MSVC)
567-
set_target_properties(volk_obj PROPERTIES COMPILE_FLAGS "-fPIC")
568-
endif()
566+
set_target_properties(volk_obj PROPERTIES POSITION_INDEPENDENT_CODE ON)
569567

570568
# Disable complex math NaN/INFO range checking for performance
571569
include(CheckCCompilerFlag)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* -*- c++ -*- */
2+
/*
3+
* Copyright 2025 Johannes Demel
4+
*
5+
* This file is part of VOLK
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*/
9+
10+
#include "volk_test.h"
11+
#include <fmt/chrono.h>
12+
#include <fmt/core.h>
13+
#include <fmt/ranges.h>
14+
#include <gtest/gtest.h>
15+
#include <volk/volk.h>
16+
#include <volk/volk_alloc.hh>
17+
#include <chrono>
18+
19+
class volk_32fc_s32fc_x2_rotator2_32fc_test : public VolkTest
20+
{
21+
protected:
22+
void SetUp() override
23+
{
24+
initialize_test(GetParam());
25+
initialize_data(vector_length);
26+
}
27+
28+
void initialize_data(const size_t length)
29+
{
30+
// Be stricter for smaller vectors. Error accumulate slowly!
31+
if (length < 16) {
32+
absolute_error = 10.e-7;
33+
} else if (length < 128) {
34+
absolute_error = 10.e-6;
35+
} else if (length < 65536) {
36+
absolute_error = 10.e-5;
37+
} else {
38+
absolute_error = 10.e-3;
39+
}
40+
41+
vector_length = length;
42+
input = volk::vector<lv_32fc_t>(length);
43+
result = volk::vector<lv_32fc_t>(length);
44+
result_magnitude = volk::vector<float>(length);
45+
46+
const float initial_phase = initial_phase_steps * increment;
47+
phase_increment = std::polar(1.0f, increment);
48+
phase = std::polar(1.0f, initial_phase);
49+
50+
for (size_t i = 0; i < length; ++i) {
51+
input[i] =
52+
std::complex<float>(2.0f * std::cos(2.0f * M_PI * i / length),
53+
2.0f * std::sin(0.3f + 2.0f * M_PI * i / length));
54+
}
55+
56+
// Calculate expected results
57+
expected = volk::vector<lv_32fc_t>(length);
58+
for (size_t i = 0; i < length; ++i) {
59+
expected[i] =
60+
input[i] *
61+
std::polar(1.0f, initial_phase + static_cast<float>(i) * increment);
62+
}
63+
64+
expected_magnitude = volk::vector<float>(length);
65+
for (size_t i = 0; i < length; ++i) {
66+
expected_magnitude[i] = std::abs(input[i]);
67+
}
68+
69+
// This is a hacky solution to have unaligned tests.
70+
ua_result = result;
71+
ua_result.at(0) = expected.at(0);
72+
}
73+
74+
void execute_aligned(const std::string impl_name)
75+
{
76+
volk_32fc_s32fc_x2_rotator2_32fc_manual(result.data(),
77+
input.data(),
78+
&phase_increment,
79+
&phase,
80+
vector_length,
81+
impl_name.c_str());
82+
83+
for (size_t i = 0; i < vector_length; ++i) {
84+
result_magnitude[i] = std::abs(result[i]);
85+
}
86+
EXPECT_TRUE(AreFloatingPointArraysEqualWithAbsoluteError(
87+
expected_magnitude, result_magnitude, absolute_magnitue_error));
88+
EXPECT_TRUE(AreComplexFloatingPointArraysEqualWithAbsoluteError(
89+
expected, result, absolute_error));
90+
}
91+
92+
void execute_unaligned(const std::string impl_name)
93+
{
94+
lv_32fc_t unaligned_phase =
95+
std::polar(1.0f, (initial_phase_steps + 1.0f) * increment);
96+
volk_32fc_s32fc_x2_rotator2_32fc_manual(ua_result.data() + 1,
97+
input.data() + 1,
98+
&phase_increment,
99+
&unaligned_phase,
100+
vector_length - 1,
101+
impl_name.c_str());
102+
for (size_t i = 0; i < vector_length; ++i) {
103+
result_magnitude[i] = std::abs(ua_result[i]);
104+
}
105+
result_magnitude[0] = expected_magnitude[0];
106+
107+
EXPECT_TRUE(AreFloatingPointArraysEqualWithAbsoluteError(
108+
expected_magnitude, result_magnitude, absolute_magnitue_error));
109+
EXPECT_TRUE(AreComplexFloatingPointArraysEqualWithAbsoluteError(
110+
expected, ua_result, absolute_error));
111+
}
112+
113+
static constexpr float increment = 0.07f;
114+
static constexpr float initial_phase_steps = 0.0f;
115+
static constexpr float absolute_magnitue_error = 1.0e-4;
116+
float absolute_error{};
117+
volk::vector<lv_32fc_t> input;
118+
volk::vector<lv_32fc_t> result;
119+
lv_32fc_t phase_increment;
120+
lv_32fc_t phase;
121+
volk::vector<lv_32fc_t> expected;
122+
volk::vector<float> expected_magnitude;
123+
volk::vector<lv_32fc_t> ua_result;
124+
volk::vector<float> result_magnitude;
125+
};
126+
127+
TEST_P(volk_32fc_s32fc_x2_rotator2_32fc_test, run)
128+
{
129+
fmt::print("test {} implementation: {:>12}, size={} ...",
130+
is_aligned_implementation ? "aligned" : "unaligned",
131+
implementation_name,
132+
vector_length);
133+
auto start = std::chrono::steady_clock::now();
134+
135+
if (is_aligned_implementation) {
136+
execute_aligned(implementation_name);
137+
} else {
138+
execute_unaligned(implementation_name);
139+
}
140+
141+
std::chrono::duration<double> elapsed = std::chrono::steady_clock::now() - start;
142+
fmt::print("\tduration={}\n", elapsed);
143+
}
144+
145+
INSTANTIATE_TEST_SUITE_P(
146+
volk_32fc_s32fc_x2_rotator2_32fc,
147+
volk_32fc_s32fc_x2_rotator2_32fc_test,
148+
testing::Combine(testing::ValuesIn(get_kernel_implementation_name_list(
149+
volk_32fc_s32fc_x2_rotator2_32fc_get_func_desc())),
150+
testing::ValuesIn(default_vector_sizes)),
151+
generate_volk_test_name());

tests/volk_test.h

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,83 @@ ::testing::AssertionResult AreComplexFloatingPointArraysAlmostEqual(const T& exp
7070
auto actual_real = ::testing::internal::FloatingPoint(actual[index].real());
7171
auto actual_imag = ::testing::internal::FloatingPoint(actual[index].imag());
7272
if (not expected_real.AlmostEquals(actual_real) or
73-
not expected_imag.AlmostEquals(actual_imag))
73+
not expected_imag.AlmostEquals(actual_imag)) {
74+
if (errorsFound == 0) {
75+
result << "Differences found:";
76+
}
77+
if (errorsFound < 3) {
78+
result << separator << expected[index] << " != " << actual[index] << " @ "
79+
<< index;
80+
separator = ",\n";
81+
}
82+
errorsFound++;
83+
}
84+
}
85+
if (errorsFound > 0) {
86+
result << separator << errorsFound << " differences in total";
87+
return result;
88+
}
89+
return ::testing::AssertionSuccess();
90+
}
91+
92+
template <class T>
93+
::testing::AssertionResult AreComplexFloatingPointArraysEqualWithAbsoluteError(
94+
const T& expected, const T& actual, const float absolute_error = 1.0e-7)
95+
{
96+
::testing::AssertionResult result = ::testing::AssertionFailure();
97+
if (expected.size() != actual.size()) {
98+
return result << "expected result size=" << expected.size()
99+
<< " differs from actual size=" << actual.size();
100+
}
101+
const unsigned long length = expected.size();
74102

75-
{
103+
int errorsFound = 0;
104+
const char* separator = " ";
105+
for (unsigned long index = 0; index < length; index++) {
106+
auto expected_real = ::testing::internal::FloatingPoint(expected[index].real());
107+
auto expected_imag = ::testing::internal::FloatingPoint(expected[index].imag());
108+
auto actual_real = ::testing::internal::FloatingPoint(actual[index].real());
109+
auto actual_imag = ::testing::internal::FloatingPoint(actual[index].imag());
110+
if (expected_real.is_nan() or actual_real.is_nan() or expected_imag.is_nan() or
111+
actual_imag.is_nan() or
112+
std::abs(expected[index].real() - actual[index].real()) > absolute_error or
113+
std::abs(expected[index].imag() - actual[index].imag()) > absolute_error) {
114+
if (errorsFound == 0) {
115+
result << "Differences found:";
116+
}
117+
if (errorsFound < 3) {
118+
result << separator << expected[index] << " != " << actual[index] << " @ "
119+
<< index;
120+
separator = ",\n";
121+
}
122+
errorsFound++;
123+
}
124+
}
125+
if (errorsFound > 0) {
126+
result << separator << errorsFound << " differences in total";
127+
return result;
128+
}
129+
return ::testing::AssertionSuccess();
130+
}
131+
132+
template <class T>
133+
::testing::AssertionResult AreFloatingPointArraysEqualWithAbsoluteError(
134+
const T& expected, const T& actual, const float absolute_error = 1.0e-7)
135+
{
136+
::testing::AssertionResult result = ::testing::AssertionFailure();
137+
if (expected.size() != actual.size()) {
138+
return result << "expected result size=" << expected.size()
139+
<< " differs from actual size=" << actual.size();
140+
}
141+
const unsigned long length = expected.size();
142+
143+
int errorsFound = 0;
144+
const char* separator = " ";
145+
for (unsigned long index = 0; index < length; index++) {
146+
auto expected_value = ::testing::internal::FloatingPoint(expected[index]);
147+
auto actual_value = ::testing::internal::FloatingPoint(actual[index]);
148+
if (expected_value.is_nan() or actual_value.is_nan() or
149+
std::abs(expected[index] - actual[index]) > absolute_error) {
76150
if (errorsFound == 0) {
77151
result << "Differences found:";
78152
}

0 commit comments

Comments
 (0)