LCOV - code coverage report
Current view: top level - test/unittests/base - atomic-utils-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 123 127 96.9 %
Date: 2017-10-20 Functions: 35 54 64.8 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <limits.h>
       6             : 
       7             : #include "src/base/atomic-utils.h"
       8             : #include "src/base/platform/platform.h"
       9             : #include "testing/gtest/include/gtest/gtest.h"
      10             : 
      11             : namespace v8 {
      12             : namespace base {
      13             : 
      14       13158 : TEST(AtomicNumber, Constructor) {
      15             :   // Test some common types.
      16             :   AtomicNumber<int> zero_int;
      17             :   AtomicNumber<size_t> zero_size_t;
      18             :   AtomicNumber<intptr_t> zero_intptr_t;
      19           2 :   EXPECT_EQ(0, zero_int.Value());
      20           2 :   EXPECT_EQ(0u, zero_size_t.Value());
      21           2 :   EXPECT_EQ(0, zero_intptr_t.Value());
      22           1 : }
      23             : 
      24             : 
      25       13158 : TEST(AtomicNumber, Value) {
      26             :   AtomicNumber<int> a(1);
      27           2 :   EXPECT_EQ(1, a.Value());
      28             :   AtomicNumber<int> b(-1);
      29           2 :   EXPECT_EQ(-1, b.Value());
      30             :   AtomicNumber<size_t> c(1);
      31           2 :   EXPECT_EQ(1u, c.Value());
      32             :   AtomicNumber<size_t> d(static_cast<size_t>(-1));
      33           2 :   EXPECT_EQ(std::numeric_limits<size_t>::max(), d.Value());
      34           1 : }
      35             : 
      36             : 
      37       13158 : TEST(AtomicNumber, SetValue) {
      38             :   AtomicNumber<int> a(1);
      39             :   a.SetValue(-1);
      40           2 :   EXPECT_EQ(-1, a.Value());
      41           1 : }
      42             : 
      43             : 
      44       13158 : TEST(AtomicNumber, Increment) {
      45             :   AtomicNumber<int> a(std::numeric_limits<int>::max());
      46             :   a.Increment(1);
      47           2 :   EXPECT_EQ(std::numeric_limits<int>::min(), a.Value());
      48             :   // Check that potential signed-ness of the underlying storage has no impact
      49             :   // on unsigned types.
      50             :   AtomicNumber<size_t> b(std::numeric_limits<intptr_t>::max());
      51             :   b.Increment(1);
      52           2 :   EXPECT_EQ(static_cast<size_t>(std::numeric_limits<intptr_t>::max()) + 1,
      53           0 :             b.Value());
      54             :   // Should work as decrement as well.
      55             :   AtomicNumber<size_t> c(1);
      56             :   c.Increment(-1);
      57           2 :   EXPECT_EQ(0u, c.Value());
      58             :   c.Increment(-1);
      59           2 :   EXPECT_EQ(std::numeric_limits<size_t>::max(), c.Value());
      60           1 : }
      61             : 
      62       13158 : TEST(AtomicNumber, Decrement) {
      63             :   AtomicNumber<size_t> a(std::numeric_limits<size_t>::max());
      64             :   a.Increment(1);
      65           2 :   EXPECT_EQ(0u, a.Value());
      66             :   a.Decrement(1);
      67           2 :   EXPECT_EQ(std::numeric_limits<size_t>::max(), a.Value());
      68           1 : }
      69             : 
      70       13158 : TEST(AtomicNumber, OperatorAdditionAssignment) {
      71             :   AtomicNumber<size_t> a(0u);
      72             :   AtomicNumber<size_t> b(std::numeric_limits<size_t>::max());
      73             :   a += b.Value();
      74           3 :   EXPECT_EQ(a.Value(), b.Value());
      75           3 :   EXPECT_EQ(b.Value(), std::numeric_limits<size_t>::max());
      76           1 : }
      77             : 
      78       13158 : TEST(AtomicNumber, OperatorSubtractionAssignment) {
      79             :   AtomicNumber<size_t> a(std::numeric_limits<size_t>::max());
      80             :   AtomicNumber<size_t> b(std::numeric_limits<size_t>::max());
      81             :   a -= b.Value();
      82           3 :   EXPECT_EQ(a.Value(), 0u);
      83           3 :   EXPECT_EQ(b.Value(), std::numeric_limits<size_t>::max());
      84           1 : }
      85             : 
      86             : namespace {
      87             : 
      88             : enum TestFlag : base::AtomicWord {
      89             :   kA,
      90             :   kB,
      91             :   kC,
      92             : };
      93             : 
      94             : }  // namespace
      95             : 
      96             : 
      97       13158 : TEST(AtomicValue, Initial) {
      98             :   AtomicValue<TestFlag> a(kA);
      99           2 :   EXPECT_EQ(TestFlag::kA, a.Value());
     100           1 : }
     101             : 
     102             : 
     103       13158 : TEST(AtomicValue, TrySetValue) {
     104             :   AtomicValue<TestFlag> a(kA);
     105           2 :   EXPECT_FALSE(a.TrySetValue(kB, kC));
     106           1 :   EXPECT_TRUE(a.TrySetValue(kA, kC));
     107           2 :   EXPECT_EQ(TestFlag::kC, a.Value());
     108           1 : }
     109             : 
     110             : 
     111       13158 : TEST(AtomicValue, SetValue) {
     112             :   AtomicValue<TestFlag> a(kB);
     113             :   a.SetValue(kC);
     114           2 :   EXPECT_EQ(TestFlag::kC, a.Value());
     115           1 : }
     116             : 
     117             : 
     118       13158 : TEST(AtomicValue, WithVoidStar) {
     119             :   AtomicValue<void*> a(nullptr);
     120             :   AtomicValue<void*> dummy(nullptr);
     121           1 :   EXPECT_EQ(nullptr, a.Value());
     122             :   a.SetValue(&a);
     123           2 :   EXPECT_EQ(&a, a.Value());
     124           2 :   EXPECT_FALSE(a.TrySetValue(nullptr, &dummy));
     125           1 :   EXPECT_TRUE(a.TrySetValue(&a, &dummy));
     126           2 :   EXPECT_EQ(&dummy, a.Value());
     127           1 : }
     128             : 
     129       13158 : TEST(AsAtomic8, CompareAndSwap_Sequential) {
     130             :   uint8_t bytes[8];
     131           9 :   for (int i = 0; i < 8; i++) {
     132           8 :     bytes[i] = 0xF0 + i;
     133             :   }
     134           8 :   for (int i = 0; i < 8; i++) {
     135          24 :     EXPECT_EQ(0xF0 + i,
     136           0 :               AsAtomic8::Release_CompareAndSwap(&bytes[i], i, 0xF7 + i));
     137             :   }
     138           8 :   for (int i = 0; i < 8; i++) {
     139          24 :     EXPECT_EQ(0xF0 + i,
     140           0 :               AsAtomic8::Release_CompareAndSwap(&bytes[i], 0xF0 + i, 0xF7 + i));
     141             :   }
     142           8 :   for (int i = 0; i < 8; i++) {
     143          16 :     EXPECT_EQ(0xF7 + i, bytes[i]);
     144             :   }
     145           1 : }
     146             : 
     147             : namespace {
     148             : 
     149          32 : class ByteIncrementingThread final : public Thread {
     150             :  public:
     151             :   ByteIncrementingThread()
     152             :       : Thread(Options("ByteIncrementingThread")),
     153             :         byte_addr_(nullptr),
     154          32 :         increments_(0) {}
     155             : 
     156             :   void Initialize(uint8_t* byte_addr, int increments) {
     157          32 :     byte_addr_ = byte_addr;
     158          32 :     increments_ = increments;
     159             :   }
     160             : 
     161          32 :   void Run() override {
     162         352 :     for (int i = 0; i < increments_; i++) {
     163         320 :       Increment();
     164             :     }
     165          32 :   }
     166             : 
     167         320 :   void Increment() {
     168             :     uint8_t byte;
     169         320 :     do {
     170         320 :       byte = AsAtomic8::Relaxed_Load(byte_addr_);
     171         320 :     } while (AsAtomic8::Release_CompareAndSwap(byte_addr_, byte, byte + 1) !=
     172             :              byte);
     173         320 :   }
     174             : 
     175             :  private:
     176             :   uint8_t* byte_addr_;
     177             :   int increments_;
     178             : };
     179             : 
     180             : }  // namespace
     181             : 
     182       13158 : TEST(AsAtomic8, CompareAndSwap_Concurrent) {
     183             :   const int kIncrements = 10;
     184             :   const int kByteCount = 8;
     185             :   uint8_t bytes[kByteCount];
     186             :   const int kThreadsPerByte = 4;
     187             :   const int kThreadCount = kByteCount * kThreadsPerByte;
     188          33 :   ByteIncrementingThread threads[kThreadCount];
     189             : 
     190           8 :   for (int i = 0; i < kByteCount; i++) {
     191           8 :     AsAtomic8::Relaxed_Store(&bytes[i], i);
     192          40 :     for (int j = 0; j < kThreadsPerByte; j++) {
     193          32 :       threads[i * kThreadsPerByte + j].Initialize(&bytes[i], kIncrements);
     194             :     }
     195             :   }
     196          32 :   for (int i = 0; i < kThreadCount; i++) {
     197          32 :     threads[i].Start();
     198             :   }
     199             : 
     200          32 :   for (int i = 0; i < kThreadCount; i++) {
     201          32 :     threads[i].Join();
     202             :   }
     203             : 
     204           8 :   for (int i = 0; i < kByteCount; i++) {
     205          24 :     EXPECT_EQ(i + kIncrements * kThreadsPerByte,
     206           0 :               AsAtomic8::Relaxed_Load(&bytes[i]));
     207          33 :   }
     208           1 : }
     209             : 
     210       13158 : TEST(AsAtomicWord, SetBits_Sequential) {
     211           1 :   uintptr_t word = 0;
     212             :   // Fill the word with a repeated 0xF0 pattern.
     213           9 :   for (unsigned i = 0; i < sizeof(word); i++) {
     214           8 :     word = (word << 8) | 0xF0;
     215             :   }
     216             :   // Check the pattern.
     217           8 :   for (unsigned i = 0; i < sizeof(word); i++) {
     218          16 :     EXPECT_EQ(0xF0u, (word >> (i * 8) & 0xFFu));
     219             :   }
     220             :   // Set the i-th byte value to i.
     221             :   uintptr_t mask = 0xFF;
     222           8 :   for (unsigned i = 0; i < sizeof(word); i++) {
     223           8 :     uintptr_t byte = static_cast<uintptr_t>(i) << (i * 8);
     224           8 :     AsAtomicWord::SetBits(&word, byte, mask);
     225           8 :     mask <<= 8;
     226             :   }
     227           9 :   for (unsigned i = 0; i < sizeof(word); i++) {
     228          16 :     EXPECT_EQ(i, (word >> (i * 8) & 0xFFu));
     229             :   }
     230           1 : }
     231             : 
     232             : namespace {
     233             : 
     234          32 : class BitSettingThread final : public Thread {
     235             :  public:
     236             :   BitSettingThread()
     237             :       : Thread(Options("BitSettingThread")),
     238             :         word_addr_(nullptr),
     239          32 :         bit_index_(0) {}
     240             : 
     241             :   void Initialize(uintptr_t* word_addr, int bit_index) {
     242          32 :     word_addr_ = word_addr;
     243          32 :     bit_index_ = bit_index;
     244             :   }
     245             : 
     246          32 :   void Run() override {
     247             :     uintptr_t bit = 1;
     248          32 :     bit = bit << bit_index_;
     249          32 :     AsAtomicWord::SetBits(word_addr_, bit, bit);
     250          32 :   }
     251             : 
     252             :  private:
     253             :   uintptr_t* word_addr_;
     254             :   int bit_index_;
     255             : };
     256             : 
     257             : }  // namespace.
     258             : 
     259       13158 : TEST(AsAtomicWord, SetBits_Concurrent) {
     260             :   const int kBitCount = sizeof(uintptr_t) * 8;
     261             :   const int kThreadCount = kBitCount / 2;
     262          33 :   BitSettingThread threads[kThreadCount];
     263             : 
     264             :   uintptr_t word;
     265             :   AsAtomicWord::Relaxed_Store(&word, 0);
     266          33 :   for (int i = 0; i < kThreadCount; i++) {
     267             :     // Thread i sets bit number i * 2.
     268          32 :     threads[i].Initialize(&word, i * 2);
     269             :   }
     270          32 :   for (int i = 0; i < kThreadCount; i++) {
     271          32 :     threads[i].Start();
     272             :   }
     273          32 :   for (int i = 0; i < kThreadCount; i++) {
     274          32 :     threads[i].Join();
     275             :   }
     276             :   uintptr_t actual_word = AsAtomicWord::Relaxed_Load(&word);
     277          65 :   for (int i = 0; i < kBitCount; i++) {
     278             :     // Every second bit must be set.
     279          64 :     uintptr_t expected = (i % 2 == 0);
     280         128 :     EXPECT_EQ(expected, actual_word & 1u);
     281          64 :     actual_word >>= 1;
     282          33 :   }
     283           1 : }
     284             : 
     285             : }  // namespace base
     286        7893 : }  // namespace v8

Generated by: LCOV version 1.10