tor-browser

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

crc_memcpy_test.cc (7042B)


      1 // Copyright 2022 The Abseil Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/crc/internal/crc_memcpy.h"
     16 
     17 #include <cstddef>
     18 #include <cstdint>
     19 #include <cstring>
     20 #include <limits>
     21 #include <memory>
     22 #include <string>
     23 #include <utility>
     24 
     25 #include "gtest/gtest.h"
     26 #include "absl/crc/crc32c.h"
     27 #include "absl/memory/memory.h"
     28 #include "absl/random/distributions.h"
     29 #include "absl/random/random.h"
     30 #include "absl/strings/str_cat.h"
     31 #include "absl/strings/string_view.h"
     32 
     33 namespace {
     34 
     35 enum CrcEngine {
     36  ACCELERATED = 0,
     37  NONTEMPORAL = 1,
     38  FALLBACK = 2,
     39 };
     40 
     41 // Correctness tests:
     42 // - Every source/destination byte alignment 0-15, every size 0-511 bytes
     43 // - Arbitrarily aligned source, large size
     44 template <size_t max_size>
     45 class CrcMemcpyTest : public testing::Test {
     46 protected:
     47  CrcMemcpyTest() {
     48    source_ = std::make_unique<char[]>(kSize);
     49    destination_ = std::make_unique<char[]>(kSize);
     50  }
     51  static constexpr size_t kAlignment = 16;
     52  static constexpr size_t kMaxCopySize = max_size;
     53  static constexpr size_t kSize = kAlignment + kMaxCopySize;
     54  std::unique_ptr<char[]> source_;
     55  std::unique_ptr<char[]> destination_;
     56 
     57  absl::BitGen gen_;
     58 };
     59 
     60 // Small test is slightly larger 4096 bytes to allow coverage of the "large"
     61 // copy function.  The minimum size to exercise all code paths in that function
     62 // would be around 256 consecutive tests (getting every possible tail value
     63 // and 0-2 small copy loops after the main block), so testing from 4096-4500
     64 // will cover all of those code paths multiple times.
     65 typedef CrcMemcpyTest<4500> CrcSmallTest;
     66 typedef CrcMemcpyTest<(1 << 24)> CrcLargeTest;
     67 // Parametrize the small test so that it can be done with all configurations.
     68 template <typename ParamsT>
     69 class EngineParamTestTemplate : public CrcSmallTest,
     70                                public ::testing::WithParamInterface<ParamsT> {
     71 protected:
     72  EngineParamTestTemplate() {
     73    if (GetParam().crc_engine_selector == FALLBACK) {
     74      engine_ = std::make_unique<absl::crc_internal::FallbackCrcMemcpyEngine>();
     75    } else if (GetParam().crc_engine_selector == NONTEMPORAL) {
     76      engine_ =
     77          std::make_unique<absl::crc_internal::CrcNonTemporalMemcpyEngine>();
     78    } else {
     79      engine_ = absl::crc_internal::CrcMemcpy::GetTestEngine(
     80          GetParam().vector_lanes, GetParam().integer_lanes);
     81    }
     82  }
     83 
     84  // Convenience method.
     85  ParamsT GetParam() const {
     86    return ::testing::WithParamInterface<ParamsT>::GetParam();
     87  }
     88 
     89  std::unique_ptr<absl::crc_internal::CrcMemcpyEngine> engine_;
     90 };
     91 struct TestParams {
     92  CrcEngine crc_engine_selector = ACCELERATED;
     93  int vector_lanes = 0;
     94  int integer_lanes = 0;
     95 };
     96 using EngineParamTest = EngineParamTestTemplate<TestParams>;
     97 // SmallCorrectness is designed to exercise every possible set of code paths
     98 // in the memcpy code, not including the loop.
     99 TEST_P(EngineParamTest, SmallCorrectnessCheckSourceAlignment) {
    100  constexpr size_t kTestSizes[] = {0, 100, 255, 512, 1024, 4000, kMaxCopySize};
    101 
    102  for (size_t source_alignment = 0; source_alignment < kAlignment;
    103       source_alignment++) {
    104    for (auto size : kTestSizes) {
    105      char* base_data = static_cast<char*>(source_.get()) + source_alignment;
    106      for (size_t i = 0; i < size; i++) {
    107        *(base_data + i) =
    108            static_cast<char>(absl::Uniform<unsigned char>(gen_));
    109      }
    110      SCOPED_TRACE(absl::StrCat("engine=<", GetParam().vector_lanes, ",",
    111                                GetParam().integer_lanes, ">, ", "size=", size,
    112                                ", source_alignment=", source_alignment));
    113      absl::crc32c_t initial_crc =
    114          absl::crc32c_t{absl::Uniform<uint32_t>(gen_)};
    115      absl::crc32c_t experiment_crc =
    116          engine_->Compute(destination_.get(), source_.get() + source_alignment,
    117                           size, initial_crc);
    118      // Check the memory region to make sure it is the same
    119      int mem_comparison =
    120          memcmp(destination_.get(), source_.get() + source_alignment, size);
    121      SCOPED_TRACE(absl::StrCat("Error in memcpy of size: ", size,
    122                                " with source alignment: ", source_alignment));
    123      ASSERT_EQ(mem_comparison, 0);
    124      absl::crc32c_t baseline_crc = absl::ExtendCrc32c(
    125          initial_crc,
    126          absl::string_view(
    127              static_cast<char*>(source_.get()) + source_alignment, size));
    128      ASSERT_EQ(baseline_crc, experiment_crc);
    129    }
    130  }
    131 }
    132 
    133 TEST_P(EngineParamTest, SmallCorrectnessCheckDestAlignment) {
    134  constexpr size_t kTestSizes[] = {0, 100, 255, 512, 1024, 4000, kMaxCopySize};
    135 
    136  for (size_t dest_alignment = 0; dest_alignment < kAlignment;
    137       dest_alignment++) {
    138    for (auto size : kTestSizes) {
    139      char* base_data = static_cast<char*>(source_.get());
    140      for (size_t i = 0; i < size; i++) {
    141        *(base_data + i) =
    142            static_cast<char>(absl::Uniform<unsigned char>(gen_));
    143      }
    144      SCOPED_TRACE(absl::StrCat("engine=<", GetParam().vector_lanes, ",",
    145                                GetParam().integer_lanes, ">, ", "size=", size,
    146                                ", destination_alignment=", dest_alignment));
    147      absl::crc32c_t initial_crc =
    148          absl::crc32c_t{absl::Uniform<uint32_t>(gen_)};
    149      absl::crc32c_t experiment_crc =
    150          engine_->Compute(destination_.get() + dest_alignment, source_.get(),
    151                           size, initial_crc);
    152      // Check the memory region to make sure it is the same
    153      int mem_comparison =
    154          memcmp(destination_.get() + dest_alignment, source_.get(), size);
    155      SCOPED_TRACE(absl::StrCat("Error in memcpy of size: ", size,
    156                                " with dest alignment: ", dest_alignment));
    157      ASSERT_EQ(mem_comparison, 0);
    158      absl::crc32c_t baseline_crc = absl::ExtendCrc32c(
    159          initial_crc,
    160          absl::string_view(static_cast<char*>(source_.get()), size));
    161      ASSERT_EQ(baseline_crc, experiment_crc);
    162    }
    163  }
    164 }
    165 
    166 INSTANTIATE_TEST_SUITE_P(EngineParamTest, EngineParamTest,
    167                         ::testing::Values(
    168                             // Tests for configurations that may occur in prod.
    169                             TestParams{ACCELERATED, 3, 0},
    170                             TestParams{ACCELERATED, 1, 2},
    171                             TestParams{ACCELERATED, 1, 0},
    172                             // Fallback test.
    173                             TestParams{FALLBACK, 0, 0},
    174                             // Non Temporal
    175                             TestParams{NONTEMPORAL, 0, 0}));
    176 
    177 }  // namespace