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 #include "v8.h" 29 30 #include "circular-queue-inl.h" 31 32 namespace v8 { 33 namespace internal { 34 35 36 SamplingCircularQueue::SamplingCircularQueue(int record_size_in_bytes, 37 int desired_chunk_size_in_bytes, 38 int buffer_size_in_chunks) 39 : record_size_(record_size_in_bytes / sizeof(Cell)), 40 chunk_size_in_bytes_(desired_chunk_size_in_bytes / record_size_in_bytes * 41 record_size_in_bytes), 42 chunk_size_(chunk_size_in_bytes_ / sizeof(Cell)), 43 buffer_size_(chunk_size_ * buffer_size_in_chunks), 44 // The distance ensures that producer and consumer never step on 45 // each other's chunks and helps eviction of produced data from 46 // the CPU cache (having that chunk size is bigger than the cache.) 47 producer_consumer_distance_(2 * chunk_size_), 48 buffer_(NewArray<Cell>(buffer_size_ + 1)) { 49 ASSERT(buffer_size_in_chunks > 2); 50 // Clean up the whole buffer to avoid encountering a random kEnd 51 // while enqueuing. 52 for (int i = 0; i < buffer_size_; ++i) { 53 buffer_[i] = kClear; 54 } 55 buffer_[buffer_size_] = kEnd; 56 57 // Layout producer and consumer position pointers each on their own 58 // cache lines to avoid cache lines thrashing due to simultaneous 59 // updates of positions by different processor cores. 60 const int positions_size = 61 RoundUp(1, kProcessorCacheLineSize) + 62 RoundUp(static_cast<int>(sizeof(ProducerPosition)), 63 kProcessorCacheLineSize) + 64 RoundUp(static_cast<int>(sizeof(ConsumerPosition)), 65 kProcessorCacheLineSize); 66 positions_ = NewArray<byte>(positions_size); 67 68 producer_pos_ = reinterpret_cast<ProducerPosition*>( 69 RoundUp(positions_, kProcessorCacheLineSize)); 70 producer_pos_->enqueue_pos = buffer_; 71 72 consumer_pos_ = reinterpret_cast<ConsumerPosition*>( 73 reinterpret_cast<byte*>(producer_pos_) + kProcessorCacheLineSize); 74 ASSERT(reinterpret_cast<byte*>(consumer_pos_ + 1) <= 75 positions_ + positions_size); 76 consumer_pos_->dequeue_chunk_pos = buffer_; 77 consumer_pos_->dequeue_chunk_poll_pos = buffer_ + producer_consumer_distance_; 78 consumer_pos_->dequeue_pos = NULL; 79 } 80 81 82 SamplingCircularQueue::~SamplingCircularQueue() { 83 DeleteArray(positions_); 84 DeleteArray(buffer_); 85 } 86 87 88 void* SamplingCircularQueue::StartDequeue() { 89 if (consumer_pos_->dequeue_pos != NULL) { 90 return consumer_pos_->dequeue_pos; 91 } else { 92 if (*consumer_pos_->dequeue_chunk_poll_pos != kClear) { 93 consumer_pos_->dequeue_pos = consumer_pos_->dequeue_chunk_pos; 94 consumer_pos_->dequeue_end_pos = consumer_pos_->dequeue_pos + chunk_size_; 95 return consumer_pos_->dequeue_pos; 96 } else { 97 return NULL; 98 } 99 } 100 } 101 102 103 void SamplingCircularQueue::FinishDequeue() { 104 consumer_pos_->dequeue_pos += record_size_; 105 if (consumer_pos_->dequeue_pos < consumer_pos_->dequeue_end_pos) return; 106 // Move to next chunk. 107 consumer_pos_->dequeue_pos = NULL; 108 *consumer_pos_->dequeue_chunk_pos = kClear; 109 consumer_pos_->dequeue_chunk_pos += chunk_size_; 110 WrapPositionIfNeeded(&consumer_pos_->dequeue_chunk_pos); 111 consumer_pos_->dequeue_chunk_poll_pos += chunk_size_; 112 WrapPositionIfNeeded(&consumer_pos_->dequeue_chunk_poll_pos); 113 } 114 115 116 void SamplingCircularQueue::FlushResidualRecords() { 117 // Eliminate producer / consumer distance. 118 consumer_pos_->dequeue_chunk_poll_pos = consumer_pos_->dequeue_chunk_pos; 119 } 120 121 122 } } // namespace v8::internal 123