File: viz_debugger_rwlock_unittest.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (145 lines) | stat: -rw-r--r-- 4,236 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <array>

#include "base/memory/raw_ptr.h"
#include "base/threading/platform_thread.h"
#include "components/viz/service/debugger/rwlock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {
// Shared global variables
int writer_count = 0;
static const unsigned kNumCounts = 1000000;

class RWLockTest : public testing::Test {
 private:
 public:
  static rwlock::RWLock test_rwlock;
};

rwlock::RWLock RWLockTest::test_rwlock;

// The writer thread reads through the entire vector at a certain
// state left by the readers, sums up all the existing integer
// values, stores it, and resets the vector to provide a blank
// slate for the reader threads to continue working on.
class WriterThread : public base::PlatformThread::Delegate {
 private:
  raw_ptr<std::vector<int>> array_;
  int size_;
  volatile int delay_counter = 0;
  static const unsigned kNumWriterTries = 100;
  static const unsigned kNumTimeDelay = 500000;

 public:
  WriterThread() = default;

  void ThreadMain() override {
    for (uint32_t writer_try = 0; writer_try < kNumWriterTries; ++writer_try) {
      RWLockTest::test_rwlock.WriteLock();

      for (int i = 0; i < size_; ++i) {
        writer_count += (*array_)[i];
        (*array_)[i] = 0;
      }
      // Reset the shared vector.
      (*array_).clear();
      (*array_).resize(size_);

      RWLockTest::test_rwlock.WriteUnLock();

      // Time delay so that the writer thread does not
      // "burn out" too fast.
      for (uint32_t _ = 0; _ < kNumTimeDelay; ++_) {
        delay_counter = delay_counter + 1;
      }
    }
  }

  void Init(std::vector<int>* array, int size) {
    array_ = array;
    size_ = size;
  }
};

// Each reader thread has a corresponding slot within the shared
// vector. Within each slot, each reader thread increments the slot's
// integer value by 1 for k number (kNumCounts) of iterations.
// Within each iteration, there is a small time buffer/delay (kNumTimeDelay)
// to allow the writer thread to squeeze and take the lock.
class ReaderThread : public base::PlatformThread::Delegate {
 private:
  static const unsigned kNumTimeDelay = 100;
  volatile int delay_counter = 0;
  raw_ptr<std::vector<int>> array_;
  int array_index;

 public:
  ReaderThread() = default;

  ReaderThread(const ReaderThread&) = delete;
  ReaderThread& operator=(const ReaderThread&) = delete;

  void ThreadMain() override {
    for (uint32_t count = 0; count < kNumCounts; ++count) {
      RWLockTest::test_rwlock.ReadLock();
      ++(*array_)[array_index];
      RWLockTest::test_rwlock.ReadUnlock();

      // Time buffer/delay element for writer to squeeze in
      for (uint32_t _ = 0; _ < kNumTimeDelay; ++_) {
        delay_counter = delay_counter + 1;
      }
    }
  }

  void Init(std::vector<int>* array, int index) {
    array_ = array;
    array_index = index;
  }
};

TEST_F(RWLockTest, ReadWrite) {
  static const unsigned kNumReaders = 4;
  std::vector<int> arr(kNumReaders);  // Must outlive `writer` and `readers`.
  WriterThread writer;
  std::array<ReaderThread, kNumReaders> readers;
  std::array<base::PlatformThreadHandle, kNumReaders> handles;

  // Initialize and start each reader thread.
  for (uint32_t i = 0; i < kNumReaders; ++i) {
    readers[i].Init(&arr, i);
  }
  for (uint32_t i = 0; i < kNumReaders; ++i) {
    ASSERT_TRUE(base::PlatformThread::Create(0, &readers[i], &handles[i]));
  }

  // Initialize and start writer thread.
  writer.Init(&arr, kNumReaders);
  base::PlatformThreadHandle writer_handle;
  ASSERT_TRUE(base::PlatformThread::Create(0, &writer, &writer_handle));

  // Collect all reader threads.
  for (auto& handle : handles) {
    base::PlatformThread::Join(handle);
  }

  // Collect writer thread.
  base::PlatformThread::Join(writer_handle);

  int total_sum = 0;

  // Add number counted by the remainder of reader threads.
  for (uint32_t i = 0; i < kNumReaders; ++i) {
    total_sum += arr[i];
  }

  // Add number counted by writer thread.
  total_sum += writer_count;

  EXPECT_EQ(static_cast<uint32_t>(total_sum), kNumReaders * kNumCounts);
}
}  // namespace