| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed 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. |
| */ |
| |
| // @author Tudor Bosman (tudorb@fb.com) |
| |
| #include <gflags/gflags.h> |
| #include <folly/Bits.h> |
| #include <folly/Benchmark.h> |
| #include <gtest/gtest.h> |
| |
| using namespace folly; |
| |
| // Test constexpr-ness. |
| #ifndef __clang__ |
| static_assert(findFirstSet(2u) == 2, "findFirstSet"); |
| static_assert(findLastSet(2u) == 2, "findLastSet"); |
| static_assert(nextPowTwo(2u) == 2, "nextPowTwo"); |
| static_assert(isPowTwo(2u), "isPowTwo"); |
| #endif // __clang__ |
| |
| namespace { |
| |
| template <class INT> |
| void testFFS() { |
| EXPECT_EQ(0, findFirstSet(static_cast<INT>(0))); |
| size_t bits = std::numeric_limits< |
| typename std::make_unsigned<INT>::type>::digits; |
| for (size_t i = 0; i < bits; i++) { |
| INT v = (static_cast<INT>(1) << (bits - 1)) | |
| (static_cast<INT>(1) << i); |
| EXPECT_EQ(i+1, findFirstSet(v)); |
| } |
| } |
| |
| template <class INT> |
| void testFLS() { |
| typedef typename std::make_unsigned<INT>::type UINT; |
| EXPECT_EQ(0, findLastSet(static_cast<INT>(0))); |
| size_t bits = std::numeric_limits<UINT>::digits; |
| for (size_t i = 0; i < bits; i++) { |
| INT v1 = static_cast<UINT>(1) << i; |
| EXPECT_EQ(i + 1, findLastSet(v1)); |
| |
| INT v2 = (static_cast<UINT>(1) << i) - 1; |
| EXPECT_EQ(i, findLastSet(v2)); |
| } |
| } |
| |
| } // namespace |
| |
| TEST(Bits, FindFirstSet) { |
| testFFS<char>(); |
| testFFS<signed char>(); |
| testFFS<unsigned char>(); |
| testFFS<short>(); |
| testFFS<unsigned short>(); |
| testFFS<int>(); |
| testFFS<unsigned int>(); |
| testFFS<long>(); |
| testFFS<unsigned long>(); |
| testFFS<long long>(); |
| testFFS<unsigned long long>(); |
| } |
| |
| TEST(Bits, FindLastSet) { |
| testFLS<char>(); |
| testFLS<signed char>(); |
| testFLS<unsigned char>(); |
| testFLS<short>(); |
| testFLS<unsigned short>(); |
| testFLS<int>(); |
| testFLS<unsigned int>(); |
| testFLS<long>(); |
| testFLS<unsigned long>(); |
| testFLS<long long>(); |
| testFLS<unsigned long long>(); |
| } |
| |
| #define testPowTwo(nextPowTwoFunc) { \ |
| EXPECT_EQ(1, nextPowTwoFunc(0u)); \ |
| EXPECT_EQ(1, nextPowTwoFunc(1u)); \ |
| EXPECT_EQ(2, nextPowTwoFunc(2u)); \ |
| EXPECT_EQ(4, nextPowTwoFunc(3u)); \ |
| EXPECT_EQ(4, nextPowTwoFunc(4u)); \ |
| EXPECT_EQ(8, nextPowTwoFunc(5u)); \ |
| EXPECT_EQ(8, nextPowTwoFunc(6u)); \ |
| EXPECT_EQ(8, nextPowTwoFunc(7u)); \ |
| EXPECT_EQ(8, nextPowTwoFunc(8u)); \ |
| EXPECT_EQ(16, nextPowTwoFunc(9u)); \ |
| EXPECT_EQ(16, nextPowTwoFunc(13u)); \ |
| EXPECT_EQ(16, nextPowTwoFunc(16u)); \ |
| EXPECT_EQ(512, nextPowTwoFunc(510u)); \ |
| EXPECT_EQ(512, nextPowTwoFunc(511u)); \ |
| EXPECT_EQ(512, nextPowTwoFunc(512u)); \ |
| EXPECT_EQ(1024, nextPowTwoFunc(513u)); \ |
| EXPECT_EQ(1024, nextPowTwoFunc(777u)); \ |
| EXPECT_EQ(1ul << 31, nextPowTwoFunc((1ul << 31) - 1)); \ |
| EXPECT_EQ(1ul << 32, nextPowTwoFunc((1ul << 32) - 1)); \ |
| EXPECT_EQ(1ull << 63, nextPowTwoFunc((1ull << 62) + 1)); \ |
| } |
| |
| |
| TEST(Bits, nextPowTwoClz) { |
| testPowTwo(nextPowTwo); |
| } |
| |
| BENCHMARK(nextPowTwoClz, iters) { |
| for (unsigned long i = 0; i < iters; ++i) { |
| auto x = folly::nextPowTwo(iters); |
| folly::doNotOptimizeAway(x); |
| } |
| } |
| |
| TEST(Bits, isPowTwo) { |
| EXPECT_FALSE(isPowTwo(0u)); |
| EXPECT_TRUE(isPowTwo(1ul)); |
| EXPECT_TRUE(isPowTwo(2ull)); |
| EXPECT_FALSE(isPowTwo(3ul)); |
| EXPECT_TRUE(isPowTwo(4ul)); |
| EXPECT_FALSE(isPowTwo(5ul)); |
| EXPECT_TRUE(isPowTwo(8ul)); |
| EXPECT_FALSE(isPowTwo(15u)); |
| EXPECT_TRUE(isPowTwo(16u)); |
| EXPECT_FALSE(isPowTwo(17u)); |
| EXPECT_FALSE(isPowTwo(511ul)); |
| EXPECT_TRUE(isPowTwo(512ul)); |
| EXPECT_FALSE(isPowTwo(513ul)); |
| EXPECT_FALSE(isPowTwo((1ul<<31) - 1)); |
| EXPECT_TRUE(isPowTwo(1ul<<31)); |
| EXPECT_FALSE(isPowTwo((1ul<<31) + 1)); |
| EXPECT_FALSE(isPowTwo((1ull<<63) - 1)); |
| EXPECT_TRUE(isPowTwo(1ull<<63)); |
| EXPECT_FALSE(isPowTwo((1ull<<63) + 1)); |
| } |
| |
| BENCHMARK_DRAW_LINE(); |
| BENCHMARK(isPowTwo, iters) { |
| bool b; |
| for (unsigned long i = 0; i < iters; ++i) { |
| b = folly::isPowTwo(i); |
| folly::doNotOptimizeAway(b); |
| } |
| } |
| |
| TEST(Bits, popcount) { |
| EXPECT_EQ(0, popcount(0U)); |
| EXPECT_EQ(1, popcount(1U)); |
| EXPECT_EQ(32, popcount(uint32_t(-1))); |
| EXPECT_EQ(64, popcount(uint64_t(-1))); |
| } |
| |
| int main(int argc, char** argv) { |
| testing::InitGoogleTest(&argc, argv); |
| gflags::ParseCommandLineFlags(&argc, &argv, true); |
| auto ret = RUN_ALL_TESTS(); |
| if (!ret && FLAGS_benchmark) { |
| folly::runBenchmarks(); |
| } |
| return ret; |
| } |
| |
| /* |
| Benchmarks run on dual Xeon X5650's @ 2.67GHz w/hyperthreading enabled |
| (12 physical cores, 12 MB cache, 72 GB RAM) |
| |
| Benchmark Iters Total t t/iter iter/sec |
| ------------------------------------------------------------------------------ |
| * nextPowTwoClz 1000000 1.659 ms 1.659 ns 574.8 M |
| */ |