tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pffft_wrapper_unittest.cc (6551B)


      1 /*
      2 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/audio_processing/utility/pffft_wrapper.h"
     12 
     13 #include <algorithm>
     14 #include <cstdlib>
     15 #include <memory>
     16 
     17 #include "api/array_view.h"
     18 #include "test/gtest.h"
     19 #include "third_party/pffft/src/pffft.h"
     20 
     21 namespace webrtc {
     22 namespace test {
     23 namespace {
     24 
     25 constexpr size_t kMaxValidSizeCheck = 1024;
     26 
     27 constexpr int kFftSizes[] = {16,   32,   64,     96,   128,  160,     192,  256,
     28                             288,  384,  5 * 96, 512,  576,  5 * 128, 800,  864,
     29                             1024, 2048, 2592,   4000, 4096, 12000,   36864};
     30 
     31 void CreatePffftWrapper(size_t fft_size, Pffft::FftType fft_type) {
     32  Pffft pffft_wrapper(fft_size, fft_type);
     33 }
     34 
     35 float* AllocateScratchBuffer(size_t fft_size, bool complex_fft) {
     36  return static_cast<float*>(
     37      pffft_aligned_malloc(fft_size * (complex_fft ? 2 : 1) * sizeof(float)));
     38 }
     39 
     40 double frand() {
     41  return std::rand() / static_cast<double>(RAND_MAX);
     42 }
     43 
     44 void ExpectArrayViewsEquality(ArrayView<const float> a,
     45                              ArrayView<const float> b) {
     46  ASSERT_EQ(a.size(), b.size());
     47  for (size_t i = 0; i < a.size(); ++i) {
     48    SCOPED_TRACE(i);
     49    EXPECT_EQ(a[i], b[i]);
     50  }
     51 }
     52 
     53 // Compares the output of the PFFFT C++ wrapper to that of the C PFFFT.
     54 // Bit-exactness is expected.
     55 void PffftValidateWrapper(size_t fft_size, bool complex_fft) {
     56  // Always use the same seed to avoid flakiness.
     57  std::srand(0);
     58 
     59  // Init PFFFT.
     60  PFFFT_Setup* pffft_status =
     61      pffft_new_setup(fft_size, complex_fft ? PFFFT_COMPLEX : PFFFT_REAL);
     62  ASSERT_TRUE(pffft_status) << "FFT size (" << fft_size << ") not supported.";
     63  size_t num_floats = fft_size * (complex_fft ? 2 : 1);
     64  int num_bytes = static_cast<int>(num_floats) * sizeof(float);
     65  float* in = static_cast<float*>(pffft_aligned_malloc(num_bytes));
     66  float* out = static_cast<float*>(pffft_aligned_malloc(num_bytes));
     67  float* scratch = AllocateScratchBuffer(fft_size, complex_fft);
     68 
     69  // Init PFFFT C++ wrapper.
     70  Pffft::FftType fft_type =
     71      complex_fft ? Pffft::FftType::kComplex : Pffft::FftType::kReal;
     72  ASSERT_TRUE(Pffft::IsValidFftSize(fft_size, fft_type));
     73  Pffft pffft_wrapper(fft_size, fft_type);
     74  auto in_wrapper = pffft_wrapper.CreateBuffer();
     75  auto out_wrapper = pffft_wrapper.CreateBuffer();
     76 
     77  // Input and output buffers views.
     78  ArrayView<float> in_view(in, num_floats);
     79  ArrayView<float> out_view(out, num_floats);
     80  auto in_wrapper_view = in_wrapper->GetView();
     81  EXPECT_EQ(in_wrapper_view.size(), num_floats);
     82  auto out_wrapper_view = out_wrapper->GetConstView();
     83  EXPECT_EQ(out_wrapper_view.size(), num_floats);
     84 
     85  // Random input data.
     86  for (size_t i = 0; i < num_floats; ++i) {
     87    in_wrapper_view[i] = in[i] = static_cast<float>(frand() * 2.0 - 1.0);
     88  }
     89 
     90  // Forward transform.
     91  pffft_transform(pffft_status, in, out, scratch, PFFFT_FORWARD);
     92  pffft_wrapper.ForwardTransform(*in_wrapper, out_wrapper.get(),
     93                                 /*ordered=*/false);
     94  ExpectArrayViewsEquality(out_view, out_wrapper_view);
     95 
     96  // Copy the FFT results into the input buffers to compute the backward FFT.
     97  std::copy(out_view.begin(), out_view.end(), in_view.begin());
     98  std::copy(out_wrapper_view.begin(), out_wrapper_view.end(),
     99            in_wrapper_view.begin());
    100 
    101  // Backward transform.
    102  pffft_transform(pffft_status, in, out, scratch, PFFFT_BACKWARD);
    103  pffft_wrapper.BackwardTransform(*in_wrapper, out_wrapper.get(),
    104                                  /*ordered=*/false);
    105  ExpectArrayViewsEquality(out_view, out_wrapper_view);
    106 
    107  pffft_destroy_setup(pffft_status);
    108  pffft_aligned_free(in);
    109  pffft_aligned_free(out);
    110  pffft_aligned_free(scratch);
    111 }
    112 
    113 }  // namespace
    114 
    115 TEST(PffftTest, CreateWrapperWithValidSize) {
    116  for (size_t fft_size = 0; fft_size < kMaxValidSizeCheck; ++fft_size) {
    117    SCOPED_TRACE(fft_size);
    118    if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal)) {
    119      CreatePffftWrapper(fft_size, Pffft::FftType::kReal);
    120    }
    121    if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex)) {
    122      CreatePffftWrapper(fft_size, Pffft::FftType::kComplex);
    123    }
    124  }
    125 }
    126 
    127 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
    128 
    129 class PffftInvalidSizeDeathTest : public ::testing::Test,
    130                                  public ::testing::WithParamInterface<size_t> {
    131 };
    132 
    133 TEST_P(PffftInvalidSizeDeathTest, DoNotCreateRealWrapper) {
    134  size_t fft_size = GetParam();
    135  ASSERT_FALSE(Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal));
    136  EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kReal), "");
    137 }
    138 
    139 TEST_P(PffftInvalidSizeDeathTest, DoNotCreateComplexWrapper) {
    140  size_t fft_size = GetParam();
    141  ASSERT_FALSE(Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex));
    142  EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kComplex), "");
    143 }
    144 
    145 INSTANTIATE_TEST_SUITE_P(PffftTest,
    146                         PffftInvalidSizeDeathTest,
    147                         ::testing::Values(17,
    148                                           33,
    149                                           65,
    150                                           97,
    151                                           129,
    152                                           161,
    153                                           193,
    154                                           257,
    155                                           289,
    156                                           385,
    157                                           481,
    158                                           513,
    159                                           577,
    160                                           641,
    161                                           801,
    162                                           865,
    163                                           1025));
    164 
    165 #endif
    166 
    167 // TODO(https://crbug.com/webrtc/9577): Enable once SIMD is always enabled.
    168 TEST(PffftTest, DISABLED_CheckSimd) {
    169  EXPECT_TRUE(Pffft::IsSimdEnabled());
    170 }
    171 
    172 TEST(PffftTest, FftBitExactness) {
    173  for (int fft_size : kFftSizes) {
    174    SCOPED_TRACE(fft_size);
    175    if (fft_size != 16) {
    176      PffftValidateWrapper(fft_size, /*complex_fft=*/false);
    177    }
    178    PffftValidateWrapper(fft_size, /*complex_fft=*/true);
    179  }
    180 }
    181 
    182 }  // namespace test
    183 }  // namespace webrtc