blob: ce9a42e81fb27535caafac60901187fb5f835f32 [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
2//
Leon Clarkef7060e22010-06-03 12:02:55 +01003// Tests of the circular queue.
Steve Block6ded16b2010-05-10 14:33:55 +01004
5#include "v8.h"
6#include "circular-queue-inl.h"
7#include "cctest.h"
8
9namespace i = v8::internal;
10
Steve Block6ded16b2010-05-10 14:33:55 +010011using i::SamplingCircularQueue;
12
13
Steve Block6ded16b2010-05-10 14:33:55 +010014TEST(SamplingCircularQueue) {
15 typedef SamplingCircularQueue::Cell Record;
16 const int kRecordsPerChunk = 4;
17 SamplingCircularQueue scq(sizeof(Record),
18 kRecordsPerChunk * sizeof(Record),
19 3);
20
21 // Check that we are using non-reserved values.
22 CHECK_NE(SamplingCircularQueue::kClear, 1);
23 CHECK_NE(SamplingCircularQueue::kEnd, 1);
24 // Fill up the first chunk.
25 CHECK_EQ(NULL, scq.StartDequeue());
26 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
27 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
28 CHECK_NE(NULL, rec);
29 *rec = i;
30 CHECK_EQ(NULL, scq.StartDequeue());
31 }
32
33 // Fill up the second chunk. Consumption must still be unavailable.
34 CHECK_EQ(NULL, scq.StartDequeue());
35 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
36 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
37 CHECK_NE(NULL, rec);
38 *rec = i;
39 CHECK_EQ(NULL, scq.StartDequeue());
40 }
41
42 Record* rec = reinterpret_cast<Record*>(scq.Enqueue());
43 CHECK_NE(NULL, rec);
44 *rec = 20;
45 // Now as we started filling up the third chunk, consumption
46 // must become possible.
47 CHECK_NE(NULL, scq.StartDequeue());
48
49 // Consume the first chunk.
50 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
51 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
52 CHECK_NE(NULL, rec);
53 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
54 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
55 scq.FinishDequeue();
56 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
57 }
58 // Now consumption must not be possible, as consumer now polls
59 // the first chunk for emptinness.
60 CHECK_EQ(NULL, scq.StartDequeue());
61
62 scq.FlushResidualRecords();
63 // From now, consumer no more polls ahead of the current chunk,
64 // so it's possible to consume the second chunk.
65 CHECK_NE(NULL, scq.StartDequeue());
66 // Consume the second chunk
67 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
68 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
69 CHECK_NE(NULL, rec);
70 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
71 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
72 scq.FinishDequeue();
73 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
74 }
75 // Consumption must still be possible as the first cell of the
76 // last chunk is not clean.
77 CHECK_NE(NULL, scq.StartDequeue());
78}
79
80
81namespace {
82
83class ProducerThread: public i::Thread {
84 public:
85 typedef SamplingCircularQueue::Cell Record;
86
87 ProducerThread(SamplingCircularQueue* scq,
88 int records_per_chunk,
89 Record value,
90 i::Semaphore* finished)
91 : scq_(scq),
92 records_per_chunk_(records_per_chunk),
93 value_(value),
94 finished_(finished) { }
95
96 virtual void Run() {
97 for (Record i = value_; i < value_ + records_per_chunk_; ++i) {
98 Record* rec = reinterpret_cast<Record*>(scq_->Enqueue());
99 CHECK_NE(NULL, rec);
100 *rec = i;
101 }
102
103 finished_->Signal();
104 }
105
106 private:
107 SamplingCircularQueue* scq_;
108 const int records_per_chunk_;
109 Record value_;
110 i::Semaphore* finished_;
111};
112
113} // namespace
114
115TEST(SamplingCircularQueueMultithreading) {
116 // Emulate multiple VM threads working 'one thread at a time.'
117 // This test enqueues data from different threads. This corresponds
118 // to the case of profiling under Linux, where signal handler that
119 // does sampling is called in the context of different VM threads.
120
121 typedef ProducerThread::Record Record;
122 const int kRecordsPerChunk = 4;
123 SamplingCircularQueue scq(sizeof(Record),
124 kRecordsPerChunk * sizeof(Record),
125 3);
126 i::Semaphore* semaphore = i::OS::CreateSemaphore(0);
127 // Don't poll ahead, making possible to check data in the buffer
128 // immediately after enqueuing.
129 scq.FlushResidualRecords();
130
131 // Check that we are using non-reserved values.
132 CHECK_NE(SamplingCircularQueue::kClear, 1);
133 CHECK_NE(SamplingCircularQueue::kEnd, 1);
134 ProducerThread producer1(&scq, kRecordsPerChunk, 1, semaphore);
135 ProducerThread producer2(&scq, kRecordsPerChunk, 10, semaphore);
136 ProducerThread producer3(&scq, kRecordsPerChunk, 20, semaphore);
137
138 CHECK_EQ(NULL, scq.StartDequeue());
139 producer1.Start();
140 semaphore->Wait();
141 for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
142 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
143 CHECK_NE(NULL, rec);
144 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
145 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
146 scq.FinishDequeue();
147 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
148 }
149
150 CHECK_EQ(NULL, scq.StartDequeue());
151 producer2.Start();
152 semaphore->Wait();
153 for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
154 Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
155 CHECK_NE(NULL, rec);
156 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec));
157 CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
158 scq.FinishDequeue();
159 CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue()));
160 }
161
162 CHECK_EQ(NULL, scq.StartDequeue());
163 producer3.Start();
164 semaphore->Wait();
165 for (Record i = 20; i < 20 + 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
176 delete semaphore;
177}