Line data Source code
1 : // Copyright 2010 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : //
28 : // Tests of the circular queue.
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/profiler/circular-queue-inl.h"
33 : #include "test/cctest/cctest.h"
34 :
35 : using i::SamplingCircularQueue;
36 :
37 :
38 26644 : TEST(SamplingCircularQueue) {
39 : typedef v8::base::AtomicWord Record;
40 : const int kMaxRecordsInQueue = 4;
41 : SamplingCircularQueue<Record, kMaxRecordsInQueue> scq;
42 :
43 : // Check that we are using non-reserved values.
44 : // Fill up the first chunk.
45 5 : CHECK(!scq.Peek());
46 45 : for (Record i = 1; i < 1 + kMaxRecordsInQueue; ++i) {
47 20 : Record* rec = reinterpret_cast<Record*>(scq.StartEnqueue());
48 20 : CHECK(rec);
49 20 : *rec = i;
50 : scq.FinishEnqueue();
51 : }
52 :
53 : // The queue is full, enqueue is not allowed.
54 5 : CHECK(!scq.StartEnqueue());
55 :
56 : // Try to enqueue when the the queue is full. Consumption must be available.
57 5 : CHECK(scq.Peek());
58 105 : for (int i = 0; i < 10; ++i) {
59 50 : Record* rec = reinterpret_cast<Record*>(scq.StartEnqueue());
60 50 : CHECK(!rec);
61 50 : CHECK(scq.Peek());
62 : }
63 :
64 : // Consume all records.
65 45 : for (Record i = 1; i < 1 + kMaxRecordsInQueue; ++i) {
66 20 : Record* rec = reinterpret_cast<Record*>(scq.Peek());
67 20 : CHECK(rec);
68 20 : CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
69 20 : CHECK_EQ(rec, reinterpret_cast<Record*>(scq.Peek()));
70 : scq.Remove();
71 20 : CHECK_NE(rec, reinterpret_cast<Record*>(scq.Peek()));
72 : }
73 : // The queue is empty.
74 5 : CHECK(!scq.Peek());
75 :
76 :
77 5 : CHECK(!scq.Peek());
78 25 : for (Record i = 0; i < kMaxRecordsInQueue / 2; ++i) {
79 10 : Record* rec = reinterpret_cast<Record*>(scq.StartEnqueue());
80 10 : CHECK(rec);
81 10 : *rec = i;
82 : scq.FinishEnqueue();
83 : }
84 :
85 : // Consume all available kMaxRecordsInQueue / 2 records.
86 5 : CHECK(scq.Peek());
87 25 : for (Record i = 0; i < kMaxRecordsInQueue / 2; ++i) {
88 10 : Record* rec = reinterpret_cast<Record*>(scq.Peek());
89 10 : CHECK(rec);
90 10 : CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
91 10 : CHECK_EQ(rec, reinterpret_cast<Record*>(scq.Peek()));
92 : scq.Remove();
93 10 : CHECK_NE(rec, reinterpret_cast<Record*>(scq.Peek()));
94 : }
95 :
96 : // The queue is empty.
97 5 : CHECK(!scq.Peek());
98 5 : }
99 :
100 :
101 : namespace {
102 :
103 : typedef v8::base::AtomicWord Record;
104 : typedef SamplingCircularQueue<Record, 12> TestSampleQueue;
105 :
106 5 : class ProducerThread: public v8::base::Thread {
107 : public:
108 : ProducerThread(TestSampleQueue* scq, int records_per_chunk, Record value,
109 : v8::base::Semaphore* finished)
110 : : Thread(Options("producer")),
111 : scq_(scq),
112 : records_per_chunk_(records_per_chunk),
113 : value_(value),
114 15 : finished_(finished) {}
115 :
116 15 : void Run() override {
117 75 : for (Record i = value_; i < value_ + records_per_chunk_; ++i) {
118 60 : Record* rec = reinterpret_cast<Record*>(scq_->StartEnqueue());
119 60 : CHECK(rec);
120 60 : *rec = i;
121 60 : scq_->FinishEnqueue();
122 : }
123 :
124 15 : finished_->Signal();
125 15 : }
126 :
127 : private:
128 : TestSampleQueue* scq_;
129 : const int records_per_chunk_;
130 : Record value_;
131 : v8::base::Semaphore* finished_;
132 : };
133 :
134 : } // namespace
135 :
136 26644 : TEST(SamplingCircularQueueMultithreading) {
137 : // Emulate multiple VM threads working 'one thread at a time.'
138 : // This test enqueues data from different threads. This corresponds
139 : // to the case of profiling under Linux, where signal handler that
140 : // does sampling is called in the context of different VM threads.
141 :
142 : const int kRecordsPerChunk = 4;
143 : TestSampleQueue scq;
144 10 : v8::base::Semaphore semaphore(0);
145 :
146 : ProducerThread producer1(&scq, kRecordsPerChunk, 1, &semaphore);
147 : ProducerThread producer2(&scq, kRecordsPerChunk, 10, &semaphore);
148 : ProducerThread producer3(&scq, kRecordsPerChunk, 20, &semaphore);
149 :
150 5 : CHECK(!scq.Peek());
151 5 : producer1.Start();
152 5 : semaphore.Wait();
153 45 : for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
154 20 : Record* rec = reinterpret_cast<Record*>(scq.Peek());
155 20 : CHECK(rec);
156 20 : CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
157 20 : CHECK_EQ(rec, reinterpret_cast<Record*>(scq.Peek()));
158 : scq.Remove();
159 20 : CHECK_NE(rec, reinterpret_cast<Record*>(scq.Peek()));
160 : }
161 :
162 5 : CHECK(!scq.Peek());
163 5 : producer2.Start();
164 5 : semaphore.Wait();
165 45 : for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
166 20 : Record* rec = reinterpret_cast<Record*>(scq.Peek());
167 20 : CHECK(rec);
168 20 : CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
169 20 : CHECK_EQ(rec, reinterpret_cast<Record*>(scq.Peek()));
170 : scq.Remove();
171 20 : CHECK_NE(rec, reinterpret_cast<Record*>(scq.Peek()));
172 : }
173 :
174 5 : CHECK(!scq.Peek());
175 5 : producer3.Start();
176 5 : semaphore.Wait();
177 45 : for (Record i = 20; i < 20 + kRecordsPerChunk; ++i) {
178 20 : Record* rec = reinterpret_cast<Record*>(scq.Peek());
179 20 : CHECK(rec);
180 20 : CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
181 20 : CHECK_EQ(rec, reinterpret_cast<Record*>(scq.Peek()));
182 : scq.Remove();
183 20 : CHECK_NE(rec, reinterpret_cast<Record*>(scq.Peek()));
184 : }
185 :
186 5 : CHECK(!scq.Peek());
187 79922 : }
|