xref: /developtools/hiperf/src/ring_buffer.cpp (revision 48f512ce)
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#define HILOG_TAG "RingBuffer"
16
17#include <linux/perf_event.h>
18#include "ring_buffer.h"
19#include "perf_event_record.h"
20#if defined(is_ohos) && is_ohos
21#include "hiperf_hilog.h"
22#endif
23
24namespace OHOS {
25namespace Developtools {
26namespace HiPerf {
27RingBuffer::RingBuffer(size_t size) : size_(size)
28{
29    if (size > 0) {
30        buf_ = std::make_unique<uint8_t[]>(size);
31    }
32}
33
34RingBuffer::~RingBuffer() {}
35
36// get size of the writable space
37size_t RingBuffer::GetFreeSize() const
38{
39    return size_ - (head_.load(std::memory_order_relaxed) - tail_.load(std::memory_order_relaxed));
40}
41
42uint8_t *RingBuffer::AllocForWrite(size_t writeSize)
43{
44    if (buf_ == nullptr || buf_.get() == nullptr) {
45        return nullptr;
46    }
47    size_t writeHead = head_.load(std::memory_order_relaxed);
48    size_t readHead = tail_.load(std::memory_order_acquire);
49    if (size_ == 0) {
50        return nullptr;
51    }
52    size_t writePos = writeHead % size_;
53    size_t readPos = readHead % size_;
54    writeSize_ = writeSize;
55    if (writePos < readPos) {
56        // |---writePos<---writeSize--->readPos---|
57        if (writePos + writeSize > readPos) {
58            return nullptr;
59        }
60    } else if (writePos == readPos and writeHead != readHead) {
61        // writePos catch up with readPos, but buffer is full
62        return nullptr;
63    } else {
64        // two cases: 1, writePos catch up with readPos, but buffer is empty
65        //            2, |---readPos---writePos<---writeSize--->|
66        if (writePos + writeSize > size_) {
67            // no enough space at the end
68            if (readPos < writeSize) {
69                return nullptr;
70            }
71            // wrap to the start, set mark byte
72            buf_.get()[writePos] = MARGIN_BYTE;
73            writeSize_ += (size_ - writePos);
74            writePos = 0;
75        }
76    }
77
78    return buf_.get() + writePos;
79}
80
81void RingBuffer::EndWrite()
82{
83    size_t head = head_.load(std::memory_order_relaxed);
84    head += writeSize_;
85    head_.store(head, std::memory_order_release);
86}
87
88uint8_t *RingBuffer::GetReadData()
89{
90    CHECK_TRUE(buf_ == nullptr || buf_.get() == nullptr, nullptr, 0, "");
91    size_t writeHead = head_.load(std::memory_order_acquire);
92    size_t readHead = tail_.load(std::memory_order_relaxed);
93    if (writeHead == readHead) {
94        return nullptr;
95    }
96
97    readSize_ = 0;
98    if (size_ == 0) {
99        return nullptr;
100    }
101    size_t writePos = writeHead % size_;
102    size_t readPos = readHead % size_;
103    if (writePos <= readPos) {
104        // |<---data2--->writePos---readPos<---data1--->|
105        if (buf_.get()[readPos] == MARGIN_BYTE) {
106            CHECK_TRUE(writePos == 0, nullptr, 0, "");
107            readSize_ = (size_ - readPos);
108            readPos = 0;
109        }
110    }
111    // else |---readPos<---data--->writePos---|
112    perf_event_header *header = reinterpret_cast<perf_event_header *>(buf_.get() + readPos);
113    CHECK_TRUE(header == nullptr, nullptr, 0, "");
114
115    if (header->type == PERF_RECORD_AUXTRACE) {
116        struct PerfRecordAuxtraceData *auxtrace = reinterpret_cast<struct PerfRecordAuxtraceData *>(header + 1);
117        readSize_ += header->size + auxtrace->size;
118    } else {
119        readSize_ += header->size;
120    }
121    return buf_.get() + readPos;
122}
123
124void RingBuffer::EndRead()
125{
126    size_t tail = tail_.load(std::memory_order_relaxed);
127    tail += readSize_;
128    tail_.store(tail, std::memory_order_release);
129}
130} // namespace HiPerf
131} // namespace Developtools
132} // namespace OHOS
133