blob: 12b593f59f714c78a27fd785047a4b4fb371944a [file] [log] [blame]
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001// Copyright 2010 the V8 project authors. All rights reserved.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002// 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.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000027//
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000028// Tests of the circular queue.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000029
30#include "v8.h"
31#include "circular-queue-inl.h"
32#include "cctest.h"
33
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000034using i::SamplingCircularQueue;
35
36
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000037TEST(SamplingCircularQueue) {
38 typedef SamplingCircularQueue::Cell Record;
39 const int kRecordsPerChunk = 4;
40 SamplingCircularQueue scq(sizeof(Record),
41 kRecordsPerChunk * sizeof(Record),
42 3);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000043
44 // Check that we are using non-reserved values.
45 CHECK_NE(SamplingCircularQueue::kClear, 1);
46 CHECK_NE(SamplingCircularQueue::kEnd, 1);
47 // Fill up the first chunk.
48 CHECK_EQ(NULL, scq.StartDequeue());
49 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
50 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
51 CHECK_NE(NULL, rec);
52 *rec = i;
53 CHECK_EQ(NULL, scq.StartDequeue());
54 }
55
56 // Fill up the second chunk. Consumption must still be unavailable.
57 CHECK_EQ(NULL, scq.StartDequeue());
58 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
59 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
60 CHECK_NE(NULL, rec);
61 *rec = i;
62 CHECK_EQ(NULL, scq.StartDequeue());
63 }
64
65 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
66 CHECK_NE(NULL, rec);
67 *rec = 20;
68 // Now as we started filling up the third chunk, consumption
69 // must become possible.
70 CHECK_NE(NULL, scq.StartDequeue());
71
72 // Consume the first chunk.
73 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
74 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
75 CHECK_NE(NULL, rec);
76 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
77 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
78 scq.FinishDequeue();
79 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
80 }
81 // Now consumption must not be possible, as consumer now polls
82 // the first chunk for emptinness.
83 CHECK_EQ(NULL, scq.StartDequeue());
84
85 scq.FlushResidualRecords();
86 // From now, consumer no more polls ahead of the current chunk,
87 // so it's possible to consume the second chunk.
88 CHECK_NE(NULL, scq.StartDequeue());
89 // Consume the second chunk
90 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
91 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
92 CHECK_NE(NULL, rec);
93 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
94 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
95 scq.FinishDequeue();
96 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
97 }
98 // Consumption must still be possible as the first cell of the
99 // last chunk is not clean.
100 CHECK_NE(NULL, scq.StartDequeue());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000101}
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000102
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000103
104namespace {
105
106class ProducerThread: public i::Thread {
107 public:
108 typedef SamplingCircularQueue::Cell Record;
109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000110 ProducerThread(SamplingCircularQueue* scq,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000111 int records_per_chunk,
112 Record value,
113 i::Semaphore* finished)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000114 : Thread("producer"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 scq_(scq),
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000116 records_per_chunk_(records_per_chunk),
117 value_(value),
118 finished_(finished) { }
119
120 virtual void Run() {
121 for (Record i = value_; i < value_ + records_per_chunk_; ++i) {
122 Record* rec = reinterpret_cast<Record*>(scq_->Enqueue());
123 CHECK_NE(NULL, rec);
124 *rec = i;
125 }
126
127 finished_->Signal();
128 }
129
130 private:
131 SamplingCircularQueue* scq_;
132 const int records_per_chunk_;
133 Record value_;
134 i::Semaphore* finished_;
135};
136
137} // namespace
138
139TEST(SamplingCircularQueueMultithreading) {
140 // Emulate multiple VM threads working 'one thread at a time.'
141 // This test enqueues data from different threads. This corresponds
142 // to the case of profiling under Linux, where signal handler that
143 // does sampling is called in the context of different VM threads.
144
145 typedef ProducerThread::Record Record;
146 const int kRecordsPerChunk = 4;
147 SamplingCircularQueue scq(sizeof(Record),
148 kRecordsPerChunk * sizeof(Record),
149 3);
150 i::Semaphore* semaphore = i::OS::CreateSemaphore(0);
151 // Don't poll ahead, making possible to check data in the buffer
152 // immediately after enqueuing.
153 scq.FlushResidualRecords();
154
155 // Check that we are using non-reserved values.
156 CHECK_NE(SamplingCircularQueue::kClear, 1);
157 CHECK_NE(SamplingCircularQueue::kEnd, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000158 ProducerThread producer1(&scq, kRecordsPerChunk, 1, semaphore);
159 ProducerThread producer2(&scq, kRecordsPerChunk, 10, semaphore);
160 ProducerThread producer3(&scq, kRecordsPerChunk, 20, semaphore);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000161
162 CHECK_EQ(NULL, scq.StartDequeue());
163 producer1.Start();
164 semaphore->Wait();
165 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
166 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
167 CHECK_NE(NULL, rec);
168 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
169 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
170 scq.FinishDequeue();
171 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
172 }
173
174 CHECK_EQ(NULL, scq.StartDequeue());
175 producer2.Start();
176 semaphore->Wait();
177 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
178 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
179 CHECK_NE(NULL, rec);
180 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
181 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
182 scq.FinishDequeue();
183 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
184 }
185
186 CHECK_EQ(NULL, scq.StartDequeue());
187 producer3.Start();
188 semaphore->Wait();
189 for (Record i = 20; i < 20 + kRecordsPerChunk; ++i) {
190 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
191 CHECK_NE(NULL, rec);
192 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
193 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
194 scq.FinishDequeue();
195 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
196 }
197
198 CHECK_EQ(NULL, scq.StartDequeue());
199
200 delete semaphore;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000201}