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/non_temporal_memcpy.h"
16
17 #include <algorithm>
18 #include <cstdint>
19 #include <iostream>
20 #include <vector>
21
22 #include "gtest/gtest.h"
23
24 namespace {
25
26 struct TestParam {
27 size_t copy_size;
28 uint32_t src_offset;
29 uint32_t dst_offset;
30 };
31
32 class NonTemporalMemcpyTest : public testing::TestWithParam<TestParam> {
33 protected:
SetUp()34 void SetUp() override {
35 // Make buf_size multiple of 16 bytes.
36 size_t buf_size = ((std::max(GetParam().src_offset, GetParam().dst_offset) +
37 GetParam().copy_size) +
38 15) /
39 16 * 16;
40 a_.resize(buf_size);
41 b_.resize(buf_size);
42 for (size_t i = 0; i < buf_size; i++) {
43 a_[i] = static_cast<uint8_t>(i % 256);
44 b_[i] = ~a_[i];
45 }
46 }
47
48 std::vector<uint8_t> a_, b_;
49 };
50
TEST_P(NonTemporalMemcpyTest,SSEEquality)51 TEST_P(NonTemporalMemcpyTest, SSEEquality) {
52 uint8_t *src = a_.data() + GetParam().src_offset;
53 uint8_t *dst = b_.data() + GetParam().dst_offset;
54 absl::crc_internal::non_temporal_store_memcpy(dst, src, GetParam().copy_size);
55 for (size_t i = 0; i < GetParam().copy_size; i++) {
56 EXPECT_EQ(src[i], dst[i]);
57 }
58 }
59
TEST_P(NonTemporalMemcpyTest,AVXEquality)60 TEST_P(NonTemporalMemcpyTest, AVXEquality) {
61 uint8_t* src = a_.data() + GetParam().src_offset;
62 uint8_t* dst = b_.data() + GetParam().dst_offset;
63
64 absl::crc_internal::non_temporal_store_memcpy_avx(dst, src,
65 GetParam().copy_size);
66 for (size_t i = 0; i < GetParam().copy_size; i++) {
67 EXPECT_EQ(src[i], dst[i]);
68 }
69 }
70
71 // 63B is smaller than one cacheline operation thus the non-temporal routine
72 // will not be called.
73 // 4352B is sufficient for testing 4092B data copy with room for offsets.
74 constexpr TestParam params[] = {
75 {63, 0, 0}, {58, 5, 5}, {61, 2, 0}, {61, 0, 2},
76 {58, 5, 2}, {4096, 0, 0}, {4096, 0, 1}, {4096, 0, 2},
77 {4096, 0, 3}, {4096, 0, 4}, {4096, 0, 5}, {4096, 0, 6},
78 {4096, 0, 7}, {4096, 0, 8}, {4096, 0, 9}, {4096, 0, 10},
79 {4096, 0, 11}, {4096, 0, 12}, {4096, 0, 13}, {4096, 0, 14},
80 {4096, 0, 15}, {4096, 7, 7}, {4096, 3, 0}, {4096, 1, 0},
81 {4096, 9, 3}, {4096, 9, 11}, {8192, 0, 0}, {8192, 5, 2},
82 {1024768, 7, 11}, {1, 0, 0}, {1, 0, 1}, {1, 1, 0},
83 {1, 1, 1}};
84
85 INSTANTIATE_TEST_SUITE_P(ParameterizedNonTemporalMemcpyTest,
86 NonTemporalMemcpyTest, testing::ValuesIn(params));
87
88 } // namespace
89