| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "kudu/util/crc.h" |
| |
| #include <cstdint> |
| #include <cstring> |
| #include <memory> |
| #include <ostream> |
| #include <utility> |
| #include <string> |
| |
| #include <glog/logging.h> |
| #include <gtest/gtest.h> |
| |
| #include "kudu/gutil/strings/numbers.h" |
| #include "kudu/gutil/strings/substitute.h" |
| #include "kudu/util/stopwatch.h" |
| #include "kudu/util/test_util.h" |
| |
| using std::unique_ptr; |
| using strings::Substitute; |
| |
| namespace kudu { |
| namespace crc { |
| |
| class CrcTest : public KuduTest { |
| protected: |
| |
| // Returns pointer to data which must be deleted by caller. |
| static void GenerateBenchmarkData(unique_ptr<uint8_t[]>* bufptr, size_t* buflen) { |
| const uint32_t kNumNumbers = 1000000; |
| const uint32_t kBytesPerNumber = sizeof(uint32_t); |
| const uint32_t kLength = kNumNumbers * kBytesPerNumber; |
| unique_ptr<uint8_t[]> buf(new uint8_t[kLength]); |
| for (uint32_t i = 0; i < kNumNumbers; i++) { |
| memcpy(buf.get() + (i * kBytesPerNumber), &i, kBytesPerNumber); |
| } |
| *bufptr = std::move(buf); |
| *buflen = kLength; |
| } |
| |
| }; |
| |
| // Basic functionality test. |
| TEST_F(CrcTest, TestCRC32C) { |
| const std::string test_data("abcdefgh"); |
| const uint64_t kExpectedCrc = 0xa9421b7; // Known value from crcutil usage test program. |
| |
| Crc* crc32c = GetCrc32cInstance(); |
| uint64_t data_crc = 0; |
| crc32c->Compute(test_data.data(), test_data.length(), &data_crc); |
| char buf[kFastToBufferSize]; |
| const char* output = FastHex64ToBuffer(data_crc, buf); |
| LOG(INFO) << "CRC32C of " << test_data << " is: 0x" << output << " (full 64 bits)"; |
| output = FastHex32ToBuffer(static_cast<uint32_t>(data_crc), buf); |
| LOG(INFO) << "CRC32C of " << test_data << " is: 0x" << output << " (truncated 32 bits)"; |
| ASSERT_EQ(kExpectedCrc, data_crc); |
| |
| // Using helper |
| uint64_t data_crc2 = Crc32c(test_data.data(), test_data.length()); |
| ASSERT_EQ(kExpectedCrc, data_crc2); |
| |
| // Using multiple chunks |
| size_t half_length = test_data.length() / 2; |
| uint64_t data_crc3 = Crc32c(test_data.data(), half_length); |
| data_crc3 = Crc32c(test_data.data() + half_length, half_length, data_crc3); |
| ASSERT_EQ(kExpectedCrc, data_crc3); |
| } |
| |
| // Simple benchmark of CRC32C throughput. |
| // We should expect about 8 bytes per cycle in throughput on a single core. |
| TEST_F(CrcTest, BenchmarkCRC32C) { |
| unique_ptr<uint8_t[]> buf; |
| size_t buflen; |
| GenerateBenchmarkData(&buf, &buflen); |
| Crc* crc32c = GetCrc32cInstance(); |
| int kNumRuns = 1000; |
| if (AllowSlowTests()) { |
| kNumRuns = 40000; |
| } |
| const uint64_t kNumBytes = kNumRuns * buflen; |
| Stopwatch sw; |
| sw.start(); |
| for (int i = 0; i < kNumRuns; i++) { |
| uint64_t cksum; |
| crc32c->Compute(buf.get(), buflen, &cksum); |
| } |
| sw.stop(); |
| CpuTimes elapsed = sw.elapsed(); |
| LOG(INFO) << Substitute("$0 runs of CRC32C on $1 bytes of data (total: $2 bytes)" |
| " in $3 seconds; $4 bytes per millisecond, $5 bytes per nanosecond!", |
| kNumRuns, buflen, kNumBytes, elapsed.wall_seconds(), |
| (kNumBytes / elapsed.wall_millis()), |
| (kNumBytes / elapsed.wall)); |
| } |
| |
| } // namespace crc |
| } // namespace kudu |