LCOV - code coverage report
Current view: top level - test/unittests/base - atomic-utils-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 81 84 96.4 %
Date: 2019-03-21 Functions: 19 30 63.3 %

          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             : namespace {
      14             : 
      15             : enum TestFlag : base::AtomicWord { kA, kB, kC };
      16             : 
      17             : }  // namespace
      18             : 
      19             : 
      20       15373 : TEST(AtomicValue, Initial) {
      21             :   AtomicValue<TestFlag> a(kA);
      22           2 :   EXPECT_EQ(TestFlag::kA, a.Value());
      23           1 : }
      24             : 
      25       15373 : TEST(AtomicValue, SetValue) {
      26             :   AtomicValue<TestFlag> a(kB);
      27             :   a.SetValue(kC);
      28           2 :   EXPECT_EQ(TestFlag::kC, a.Value());
      29           1 : }
      30             : 
      31             : 
      32       15373 : TEST(AtomicValue, WithVoidStar) {
      33             :   AtomicValue<void*> a(nullptr);
      34             :   AtomicValue<void*> dummy(nullptr);
      35           1 :   EXPECT_EQ(nullptr, a.Value());
      36             :   a.SetValue(&a);
      37           2 :   EXPECT_EQ(&a, a.Value());
      38           1 : }
      39             : 
      40       15373 : TEST(AsAtomic8, CompareAndSwap_Sequential) {
      41             :   uint8_t bytes[8];
      42          17 :   for (int i = 0; i < 8; i++) {
      43           8 :     bytes[i] = 0xF0 + i;
      44             :   }
      45          17 :   for (int i = 0; i < 8; i++) {
      46          24 :     EXPECT_EQ(0xF0 + i,
      47           0 :               AsAtomic8::Release_CompareAndSwap(&bytes[i], i, 0xF7 + i));
      48             :   }
      49          17 :   for (int i = 0; i < 8; i++) {
      50          24 :     EXPECT_EQ(0xF0 + i,
      51           0 :               AsAtomic8::Release_CompareAndSwap(&bytes[i], 0xF0 + i, 0xF7 + i));
      52             :   }
      53          17 :   for (int i = 0; i < 8; i++) {
      54          16 :     EXPECT_EQ(0xF7 + i, bytes[i]);
      55             :   }
      56           1 : }
      57             : 
      58             : namespace {
      59             : 
      60          32 : class ByteIncrementingThread final : public Thread {
      61             :  public:
      62             :   ByteIncrementingThread()
      63             :       : Thread(Options("ByteIncrementingThread")),
      64             :         byte_addr_(nullptr),
      65          32 :         increments_(0) {}
      66             : 
      67             :   void Initialize(uint8_t* byte_addr, int increments) {
      68          32 :     byte_addr_ = byte_addr;
      69          32 :     increments_ = increments;
      70             :   }
      71             : 
      72          32 :   void Run() override {
      73         672 :     for (int i = 0; i < increments_; i++) {
      74         320 :       Increment();
      75             :     }
      76          32 :   }
      77             : 
      78         320 :   void Increment() {
      79             :     uint8_t byte;
      80         320 :     do {
      81         320 :       byte = AsAtomic8::Relaxed_Load(byte_addr_);
      82         320 :     } while (AsAtomic8::Release_CompareAndSwap(byte_addr_, byte, byte + 1) !=
      83             :              byte);
      84         320 :   }
      85             : 
      86             :  private:
      87             :   uint8_t* byte_addr_;
      88             :   int increments_;
      89             : };
      90             : 
      91             : }  // namespace
      92             : 
      93       15373 : TEST(AsAtomic8, CompareAndSwap_Concurrent) {
      94             :   const int kIncrements = 10;
      95             :   const int kByteCount = 8;
      96             :   uint8_t bytes[kByteCount];
      97             :   const int kThreadsPerByte = 4;
      98             :   const int kThreadCount = kByteCount * kThreadsPerByte;
      99          98 :   ByteIncrementingThread threads[kThreadCount];
     100             : 
     101          17 :   for (int i = 0; i < kByteCount; i++) {
     102           8 :     AsAtomic8::Relaxed_Store(&bytes[i], i);
     103          72 :     for (int j = 0; j < kThreadsPerByte; j++) {
     104          32 :       threads[i * kThreadsPerByte + j].Initialize(&bytes[i], kIncrements);
     105             :     }
     106             :   }
     107          65 :   for (int i = 0; i < kThreadCount; i++) {
     108          32 :     threads[i].Start();
     109             :   }
     110             : 
     111          65 :   for (int i = 0; i < kThreadCount; i++) {
     112          32 :     threads[i].Join();
     113             :   }
     114             : 
     115          17 :   for (int i = 0; i < kByteCount; i++) {
     116          24 :     EXPECT_EQ(i + kIncrements * kThreadsPerByte,
     117           0 :               AsAtomic8::Relaxed_Load(&bytes[i]));
     118             :   }
     119           1 : }
     120             : 
     121       15373 : TEST(AsAtomicWord, SetBits_Sequential) {
     122           1 :   uintptr_t word = 0;
     123             :   // Fill the word with a repeated 0xF0 pattern.
     124          17 :   for (unsigned i = 0; i < sizeof(word); i++) {
     125           8 :     word = (word << 8) | 0xF0;
     126             :   }
     127             :   // Check the pattern.
     128          17 :   for (unsigned i = 0; i < sizeof(word); i++) {
     129          16 :     EXPECT_EQ(0xF0u, (word >> (i * 8) & 0xFFu));
     130             :   }
     131             :   // Set the i-th byte value to i.
     132             :   uintptr_t mask = 0xFF;
     133          17 :   for (unsigned i = 0; i < sizeof(word); i++) {
     134           8 :     uintptr_t byte = static_cast<uintptr_t>(i) << (i * 8);
     135           8 :     AsAtomicWord::SetBits(&word, byte, mask);
     136           8 :     mask <<= 8;
     137             :   }
     138           9 :   for (unsigned i = 0; i < sizeof(word); i++) {
     139          16 :     EXPECT_EQ(i, (word >> (i * 8) & 0xFFu));
     140             :   }
     141           1 : }
     142             : 
     143             : namespace {
     144             : 
     145          32 : class BitSettingThread final : public Thread {
     146             :  public:
     147             :   BitSettingThread()
     148             :       : Thread(Options("BitSettingThread")),
     149             :         word_addr_(nullptr),
     150          32 :         bit_index_(0) {}
     151             : 
     152             :   void Initialize(uintptr_t* word_addr, int bit_index) {
     153          32 :     word_addr_ = word_addr;
     154          32 :     bit_index_ = bit_index;
     155             :   }
     156             : 
     157          32 :   void Run() override {
     158             :     uintptr_t bit = 1;
     159          32 :     bit = bit << bit_index_;
     160          32 :     AsAtomicWord::SetBits(word_addr_, bit, bit);
     161          32 :   }
     162             : 
     163             :  private:
     164             :   uintptr_t* word_addr_;
     165             :   int bit_index_;
     166             : };
     167             : 
     168             : }  // namespace.
     169             : 
     170       15373 : TEST(AsAtomicWord, SetBits_Concurrent) {
     171             :   const int kBitCount = sizeof(uintptr_t) * 8;
     172             :   const int kThreadCount = kBitCount / 2;
     173          98 :   BitSettingThread threads[kThreadCount];
     174             : 
     175             :   uintptr_t word;
     176             :   AsAtomicWord::Relaxed_Store(&word, 0);
     177          65 :   for (int i = 0; i < kThreadCount; i++) {
     178             :     // Thread i sets bit number i * 2.
     179          32 :     threads[i].Initialize(&word, i * 2);
     180             :   }
     181          65 :   for (int i = 0; i < kThreadCount; i++) {
     182          32 :     threads[i].Start();
     183             :   }
     184          65 :   for (int i = 0; i < kThreadCount; i++) {
     185          32 :     threads[i].Join();
     186             :   }
     187             :   uintptr_t actual_word = AsAtomicWord::Relaxed_Load(&word);
     188         129 :   for (int i = 0; i < kBitCount; i++) {
     189             :     // Every second bit must be set.
     190          64 :     uintptr_t expected = (i % 2 == 0);
     191         128 :     EXPECT_EQ(expected, actual_word & 1u);
     192          64 :     actual_word >>= 1;
     193             :   }
     194           1 : }
     195             : 
     196             : }  // namespace base
     197        9222 : }  // namespace v8

Generated by: LCOV version 1.10