xref: /aosp_15_r20/external/perfetto/src/base/metatrace_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include <array>
18*6dbdd20aSAndroid Build Coastguard Worker #include <atomic>
19*6dbdd20aSAndroid Build Coastguard Worker #include <chrono>
20*6dbdd20aSAndroid Build Coastguard Worker #include <deque>
21*6dbdd20aSAndroid Build Coastguard Worker #include <thread>
22*6dbdd20aSAndroid Build Coastguard Worker 
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/metatrace.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_annotations.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "src/base/test/test_task_runner.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
27*6dbdd20aSAndroid Build Coastguard Worker 
28*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
29*6dbdd20aSAndroid Build Coastguard Worker namespace {
30*6dbdd20aSAndroid Build Coastguard Worker 
31*6dbdd20aSAndroid Build Coastguard Worker namespace m = ::perfetto::metatrace;
32*6dbdd20aSAndroid Build Coastguard Worker using ::testing::Invoke;
33*6dbdd20aSAndroid Build Coastguard Worker 
34*6dbdd20aSAndroid Build Coastguard Worker class MetatraceTest : public ::testing::Test {
35*6dbdd20aSAndroid Build Coastguard Worker  public:
SetUp()36*6dbdd20aSAndroid Build Coastguard Worker   void SetUp() override { m::Disable(); }
37*6dbdd20aSAndroid Build Coastguard Worker 
TearDown()38*6dbdd20aSAndroid Build Coastguard Worker   void TearDown() override {
39*6dbdd20aSAndroid Build Coastguard Worker     task_runner_.RunUntilIdle();
40*6dbdd20aSAndroid Build Coastguard Worker     m::Disable();
41*6dbdd20aSAndroid Build Coastguard Worker   }
42*6dbdd20aSAndroid Build Coastguard Worker 
Enable(uint32_t tags)43*6dbdd20aSAndroid Build Coastguard Worker   void Enable(uint32_t tags) {
44*6dbdd20aSAndroid Build Coastguard Worker     m::Enable([this] { ReadCallback(); }, &task_runner_, tags);
45*6dbdd20aSAndroid Build Coastguard Worker   }
46*6dbdd20aSAndroid Build Coastguard Worker 
47*6dbdd20aSAndroid Build Coastguard Worker   MOCK_METHOD(void, ReadCallback, ());
48*6dbdd20aSAndroid Build Coastguard Worker   base::TestTaskRunner task_runner_;
49*6dbdd20aSAndroid Build Coastguard Worker };
50*6dbdd20aSAndroid Build Coastguard Worker 
TEST_F(MetatraceTest,TagEnablingLogic)51*6dbdd20aSAndroid Build Coastguard Worker TEST_F(MetatraceTest, TagEnablingLogic) {
52*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*this, ReadCallback()).Times(0);
53*6dbdd20aSAndroid Build Coastguard Worker   for (int iteration = 0; iteration < 3; iteration++) {
54*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), 0u);
55*6dbdd20aSAndroid Build Coastguard Worker 
56*6dbdd20aSAndroid Build Coastguard Worker     // No events should be traced before enabling.
57*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(m::TAG_ANY, /*id=*/1, /*value=*/42);
58*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(m::TAG_ANY, /*id=*/1); }
59*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), 0u);
60*6dbdd20aSAndroid Build Coastguard Worker 
61*6dbdd20aSAndroid Build Coastguard Worker     // Enable tags bit 1 (=2) and 2 (=4) and verify that only those events are
62*6dbdd20aSAndroid Build Coastguard Worker     // added.
63*6dbdd20aSAndroid Build Coastguard Worker     auto t_start = metatrace::TraceTimeNowNs();
64*6dbdd20aSAndroid Build Coastguard Worker     Enable(/*tags=*/2 | 4);
65*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/1, /*id=*/42, /*value=*/10);      // No.
66*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/2, /*id=*/42, /*value=*/11);      // Yes.
67*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/4, /*id=*/42, /*value=*/12);      // Yes.
68*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/1 | 2, /*id=*/42, /*value=*/13);  // Yes.
69*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/1 | 4, /*id=*/42, /*value=*/14);  // Yes.
70*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/2 | 4, /*id=*/42, /*value=*/15);  // Yes.
71*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/4 | 8, /*id=*/42, /*value=*/16);  // Yes.
72*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(/*tag=*/1 | 8, /*id=*/42, /*value=*/17);  // No.
73*6dbdd20aSAndroid Build Coastguard Worker     m::TraceCounter(m::TAG_ANY, /*id=*/42, /*value=*/18);     // Yes.
74*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(/*tag=*/1, /*id=*/20); }             // No.
75*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(/*tag=*/8, /*id=*/21); }             // No.
76*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(/*tag=*/2, /*id=*/22); }             // Yes.
77*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(/*tag=*/4 | 8, /*id=*/23); }         // Yes.
78*6dbdd20aSAndroid Build Coastguard Worker     { m::ScopedEvent evt(m::TAG_ANY, /*id=*/24); }            // Yes.
79*6dbdd20aSAndroid Build Coastguard Worker 
80*6dbdd20aSAndroid Build Coastguard Worker     {
81*6dbdd20aSAndroid Build Coastguard Worker       auto it = m::RingBuffer::GetReadIterator();
82*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(it);
83*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 11);
84*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
85*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 12);
86*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
87*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 13);
88*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
89*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 14);
90*6dbdd20aSAndroid Build Coastguard Worker     }
91*6dbdd20aSAndroid Build Coastguard Worker 
92*6dbdd20aSAndroid Build Coastguard Worker     // Test that destroying and re-creating the iterator resumes reading from
93*6dbdd20aSAndroid Build Coastguard Worker     // the right place.
94*6dbdd20aSAndroid Build Coastguard Worker     {
95*6dbdd20aSAndroid Build Coastguard Worker       auto it = m::RingBuffer::GetReadIterator();
96*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
97*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 15);
98*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
99*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 16);
100*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
101*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, 18);
102*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
103*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->type_and_id, 22);
104*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
105*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->type_and_id, 23);
106*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(++it);
107*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->type_and_id, 24);
108*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_FALSE(++it);
109*6dbdd20aSAndroid Build Coastguard Worker     }
110*6dbdd20aSAndroid Build Coastguard Worker 
111*6dbdd20aSAndroid Build Coastguard Worker     // Test that we can write pids up to 32 bit TIDs (I observed up to 262144
112*6dbdd20aSAndroid Build Coastguard Worker     // from /proc/sys/kernel/pid_max) and up to 2 days of timestamps.
113*6dbdd20aSAndroid Build Coastguard Worker     {
114*6dbdd20aSAndroid Build Coastguard Worker       auto* record = m::RingBuffer::AppendNewRecord();
115*6dbdd20aSAndroid Build Coastguard Worker       record->counter_value = 42;
116*6dbdd20aSAndroid Build Coastguard Worker       constexpr uint64_t kTwoDays = 48ULL * 3600 * 1000 * 1000 * 1000;
117*6dbdd20aSAndroid Build Coastguard Worker       record->set_timestamp(t_start + kTwoDays);
118*6dbdd20aSAndroid Build Coastguard Worker       record->thread_id = 0xbabaf00d;
119*6dbdd20aSAndroid Build Coastguard Worker       record->type_and_id = m::Record::kTypeCounter;
120*6dbdd20aSAndroid Build Coastguard Worker 
121*6dbdd20aSAndroid Build Coastguard Worker       auto it = m::RingBuffer::GetReadIterator();
122*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_TRUE(it);
123*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->timestamp_ns(), t_start + kTwoDays);
124*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->thread_id, 0xbabaf00d);
125*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_FALSE(++it);
126*6dbdd20aSAndroid Build Coastguard Worker     }
127*6dbdd20aSAndroid Build Coastguard Worker 
128*6dbdd20aSAndroid Build Coastguard Worker     m::Disable();
129*6dbdd20aSAndroid Build Coastguard Worker   }
130*6dbdd20aSAndroid Build Coastguard Worker }
131*6dbdd20aSAndroid Build Coastguard Worker 
132*6dbdd20aSAndroid Build Coastguard Worker // Test that overruns are handled properly and that the writer re-synchronizes
133*6dbdd20aSAndroid Build Coastguard Worker // after the reader catches up.
TEST_F(MetatraceTest,HandleOverruns)134*6dbdd20aSAndroid Build Coastguard Worker TEST_F(MetatraceTest, HandleOverruns) {
135*6dbdd20aSAndroid Build Coastguard Worker   int cnt = 0;
136*6dbdd20aSAndroid Build Coastguard Worker   int exp_cnt = 0;
137*6dbdd20aSAndroid Build Coastguard Worker   for (size_t iteration = 0; iteration < 3; iteration++) {
138*6dbdd20aSAndroid Build Coastguard Worker     Enable(m::TAG_ANY);
139*6dbdd20aSAndroid Build Coastguard Worker     std::string checkpoint_name = "ReadTask " + std::to_string(iteration);
140*6dbdd20aSAndroid Build Coastguard Worker     auto checkpoint = task_runner_.CreateCheckpoint(checkpoint_name);
141*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_CALL(*this, ReadCallback()).WillOnce(Invoke(checkpoint));
142*6dbdd20aSAndroid Build Coastguard Worker 
143*6dbdd20aSAndroid Build Coastguard Worker     for (size_t i = 0; i < m::RingBuffer::kCapacity; i++)
144*6dbdd20aSAndroid Build Coastguard Worker       m::TraceCounter(/*tag=*/1, /*id=*/42, /*value=*/cnt++);
145*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), m::RingBuffer::kCapacity);
146*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(m::RingBuffer::has_overruns());
147*6dbdd20aSAndroid Build Coastguard Worker 
148*6dbdd20aSAndroid Build Coastguard Worker     for (int n = 0; n < 3; n++)
149*6dbdd20aSAndroid Build Coastguard Worker       m::TraceCounter(/*tag=*/1, /*id=*/42, /*value=*/-1);  // Will overrun.
150*6dbdd20aSAndroid Build Coastguard Worker 
151*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(m::RingBuffer::has_overruns());
152*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), m::RingBuffer::kCapacity);
153*6dbdd20aSAndroid Build Coastguard Worker 
154*6dbdd20aSAndroid Build Coastguard Worker     for (auto it = m::RingBuffer::GetReadIterator(); it; ++it)
155*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, exp_cnt++);
156*6dbdd20aSAndroid Build Coastguard Worker 
157*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), 0u);
158*6dbdd20aSAndroid Build Coastguard Worker 
159*6dbdd20aSAndroid Build Coastguard Worker     task_runner_.RunUntilCheckpoint(checkpoint_name);
160*6dbdd20aSAndroid Build Coastguard Worker     m::Disable();
161*6dbdd20aSAndroid Build Coastguard Worker   }
162*6dbdd20aSAndroid Build Coastguard Worker }
163*6dbdd20aSAndroid Build Coastguard Worker 
164*6dbdd20aSAndroid Build Coastguard Worker // Sets up a scenario where the writer writes constantly (however, guaranteeing
165*6dbdd20aSAndroid Build Coastguard Worker // to not overrun) and the reader catches up. Tests that all events are seen
166*6dbdd20aSAndroid Build Coastguard Worker // consistently without gaps.
TEST_F(MetatraceTest,InterleavedReadWrites)167*6dbdd20aSAndroid Build Coastguard Worker TEST_F(MetatraceTest, InterleavedReadWrites) {
168*6dbdd20aSAndroid Build Coastguard Worker   Enable(m::TAG_ANY);
169*6dbdd20aSAndroid Build Coastguard Worker   constexpr int kMaxValue = m::RingBuffer::kCapacity * 3;
170*6dbdd20aSAndroid Build Coastguard Worker 
171*6dbdd20aSAndroid Build Coastguard Worker   std::atomic<int> last_value_read{-1};
172*6dbdd20aSAndroid Build Coastguard Worker   auto read_task = [&last_value_read] {
173*6dbdd20aSAndroid Build Coastguard Worker     int last = last_value_read;
174*6dbdd20aSAndroid Build Coastguard Worker     for (auto it = m::RingBuffer::GetReadIterator(); it; ++it) {
175*6dbdd20aSAndroid Build Coastguard Worker       if (it->type_and_id.load(std::memory_order_acquire) == 0)
176*6dbdd20aSAndroid Build Coastguard Worker         break;
177*6dbdd20aSAndroid Build Coastguard Worker       // TSan doesn't know about the happens-before relationship between the
178*6dbdd20aSAndroid Build Coastguard Worker       // type_and_id marker and the value being valid. Fixing this properly
179*6dbdd20aSAndroid Build Coastguard Worker       // would require making all accesses to the metatrace object as
180*6dbdd20aSAndroid Build Coastguard Worker       // std::atomic and read them with memory_order_relaxed, which is overkill.
181*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(&it->counter_value, sizeof(int), "")
182*6dbdd20aSAndroid Build Coastguard Worker       int32_t counter_value = it->counter_value;
183*6dbdd20aSAndroid Build Coastguard Worker       EXPECT_EQ(counter_value, last + 1);
184*6dbdd20aSAndroid Build Coastguard Worker       last = counter_value;
185*6dbdd20aSAndroid Build Coastguard Worker     }
186*6dbdd20aSAndroid Build Coastguard Worker     // The read pointer is incremented only after destroying the iterator.
187*6dbdd20aSAndroid Build Coastguard Worker     // Publish the last read value after the loop.
188*6dbdd20aSAndroid Build Coastguard Worker     last_value_read = last;
189*6dbdd20aSAndroid Build Coastguard Worker   };
190*6dbdd20aSAndroid Build Coastguard Worker 
191*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_CALL(*this, ReadCallback()).WillRepeatedly(Invoke(read_task));
192*6dbdd20aSAndroid Build Coastguard Worker 
193*6dbdd20aSAndroid Build Coastguard Worker   // The writer will write continuously counters from 0 to kMaxValue.
194*6dbdd20aSAndroid Build Coastguard Worker   auto writer_done = task_runner_.CreateCheckpoint("writer_done");
195*6dbdd20aSAndroid Build Coastguard Worker   std::thread writer_thread([this, &writer_done, &last_value_read] {
196*6dbdd20aSAndroid Build Coastguard Worker     for (int i = 0; i < kMaxValue; i++) {
197*6dbdd20aSAndroid Build Coastguard Worker       m::TraceCounter(/*tag=*/1, /*id=*/1, i);
198*6dbdd20aSAndroid Build Coastguard Worker       const int kCapacity = static_cast<int>(m::RingBuffer::kCapacity);
199*6dbdd20aSAndroid Build Coastguard Worker 
200*6dbdd20aSAndroid Build Coastguard Worker       // Wait for the reader to avoid overruns.
201*6dbdd20aSAndroid Build Coastguard Worker       // Using memory_order_relaxed because the QEMU arm emulator seems to incur
202*6dbdd20aSAndroid Build Coastguard Worker       // in very high costs when dealing with full barriers, causing timeouts.
203*6dbdd20aSAndroid Build Coastguard Worker       for (int sleep_us = 1;
204*6dbdd20aSAndroid Build Coastguard Worker            i - last_value_read.load(std::memory_order_relaxed) >= kCapacity - 1;
205*6dbdd20aSAndroid Build Coastguard Worker            sleep_us = std::min(sleep_us * 10, 1000)) {
206*6dbdd20aSAndroid Build Coastguard Worker         std::this_thread::sleep_for(std::chrono::microseconds(sleep_us));
207*6dbdd20aSAndroid Build Coastguard Worker       }
208*6dbdd20aSAndroid Build Coastguard Worker     }
209*6dbdd20aSAndroid Build Coastguard Worker     task_runner_.PostTask(writer_done);
210*6dbdd20aSAndroid Build Coastguard Worker   });
211*6dbdd20aSAndroid Build Coastguard Worker 
212*6dbdd20aSAndroid Build Coastguard Worker   task_runner_.RunUntilCheckpoint("writer_done");
213*6dbdd20aSAndroid Build Coastguard Worker   writer_thread.join();
214*6dbdd20aSAndroid Build Coastguard Worker 
215*6dbdd20aSAndroid Build Coastguard Worker   read_task();  // Do a final read pass.
216*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(m::RingBuffer::has_overruns());
217*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(last_value_read, kMaxValue - 1);
218*6dbdd20aSAndroid Build Coastguard Worker }
219*6dbdd20aSAndroid Build Coastguard Worker 
220*6dbdd20aSAndroid Build Coastguard Worker // Try to hit potential thread races:
221*6dbdd20aSAndroid Build Coastguard Worker // - Test that the read callback is posted only once per cycle.
222*6dbdd20aSAndroid Build Coastguard Worker // - Test that the final size of the ring buffeer is sane.
223*6dbdd20aSAndroid Build Coastguard Worker // - Test that event records are consistent within each thread's event stream.
TEST_F(MetatraceTest,ThreadRaces)224*6dbdd20aSAndroid Build Coastguard Worker TEST_F(MetatraceTest, ThreadRaces) {
225*6dbdd20aSAndroid Build Coastguard Worker   for (size_t iteration = 0; iteration < 10; iteration++) {
226*6dbdd20aSAndroid Build Coastguard Worker     Enable(m::TAG_ANY);
227*6dbdd20aSAndroid Build Coastguard Worker 
228*6dbdd20aSAndroid Build Coastguard Worker     std::string checkpoint_name = "ReadTask " + std::to_string(iteration);
229*6dbdd20aSAndroid Build Coastguard Worker     auto checkpoint = task_runner_.CreateCheckpoint(checkpoint_name);
230*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_CALL(*this, ReadCallback()).WillOnce(Invoke(checkpoint));
231*6dbdd20aSAndroid Build Coastguard Worker 
232*6dbdd20aSAndroid Build Coastguard Worker     auto thread_main = [](uint16_t thd_idx) {
233*6dbdd20aSAndroid Build Coastguard Worker       for (size_t i = 0; i < m::RingBuffer::kCapacity + 500; i++)
234*6dbdd20aSAndroid Build Coastguard Worker         m::TraceCounter(/*tag=*/1, thd_idx, static_cast<int>(i));
235*6dbdd20aSAndroid Build Coastguard Worker     };
236*6dbdd20aSAndroid Build Coastguard Worker 
237*6dbdd20aSAndroid Build Coastguard Worker     constexpr size_t kNumThreads = 8;
238*6dbdd20aSAndroid Build Coastguard Worker     std::array<std::thread, kNumThreads> threads;
239*6dbdd20aSAndroid Build Coastguard Worker     for (size_t thd_idx = 0; thd_idx < kNumThreads; thd_idx++)
240*6dbdd20aSAndroid Build Coastguard Worker       threads[thd_idx] = std::thread(thread_main, thd_idx);
241*6dbdd20aSAndroid Build Coastguard Worker 
242*6dbdd20aSAndroid Build Coastguard Worker     for (auto& t : threads)
243*6dbdd20aSAndroid Build Coastguard Worker       t.join();
244*6dbdd20aSAndroid Build Coastguard Worker 
245*6dbdd20aSAndroid Build Coastguard Worker     task_runner_.RunUntilCheckpoint(checkpoint_name);
246*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(m::RingBuffer::GetSizeForTesting(), m::RingBuffer::kCapacity);
247*6dbdd20aSAndroid Build Coastguard Worker 
248*6dbdd20aSAndroid Build Coastguard Worker     std::array<int, kNumThreads> last_val{};  // Last value for each thread.
249*6dbdd20aSAndroid Build Coastguard Worker     for (auto it = m::RingBuffer::GetReadIterator(); it; ++it) {
250*6dbdd20aSAndroid Build Coastguard Worker       if (it->type_and_id.load(std::memory_order_acquire) == 0)
251*6dbdd20aSAndroid Build Coastguard Worker         break;
252*6dbdd20aSAndroid Build Coastguard Worker       using Record = m::Record;
253*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->type_and_id & Record::kTypeMask, Record::kTypeCounter);
254*6dbdd20aSAndroid Build Coastguard Worker       auto thd_idx = static_cast<size_t>(it->type_and_id & ~Record::kTypeMask);
255*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(it->counter_value, last_val[thd_idx]);
256*6dbdd20aSAndroid Build Coastguard Worker       last_val[thd_idx]++;
257*6dbdd20aSAndroid Build Coastguard Worker     }
258*6dbdd20aSAndroid Build Coastguard Worker 
259*6dbdd20aSAndroid Build Coastguard Worker     m::Disable();
260*6dbdd20aSAndroid Build Coastguard Worker   }
261*6dbdd20aSAndroid Build Coastguard Worker }
262*6dbdd20aSAndroid Build Coastguard Worker 
263*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
264*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
265