148f512ceSopenharmony_ci/*
248f512ceSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
448f512ceSopenharmony_ci * you may not use this file except in compliance with the License.
548f512ceSopenharmony_ci * You may obtain a copy of the License at
648f512ceSopenharmony_ci *
748f512ceSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
848f512ceSopenharmony_ci *
948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and
1348f512ceSopenharmony_ci * limitations under the License.
1448f512ceSopenharmony_ci */
1548f512ceSopenharmony_ci#define HILOG_TAG "RingBuffer"
1648f512ceSopenharmony_ci
1748f512ceSopenharmony_ci#include <linux/perf_event.h>
1848f512ceSopenharmony_ci#include "ring_buffer.h"
1948f512ceSopenharmony_ci#include "perf_event_record.h"
2048f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos
2148f512ceSopenharmony_ci#include "hiperf_hilog.h"
2248f512ceSopenharmony_ci#endif
2348f512ceSopenharmony_ci
2448f512ceSopenharmony_cinamespace OHOS {
2548f512ceSopenharmony_cinamespace Developtools {
2648f512ceSopenharmony_cinamespace HiPerf {
2748f512ceSopenharmony_ciRingBuffer::RingBuffer(size_t size) : size_(size)
2848f512ceSopenharmony_ci{
2948f512ceSopenharmony_ci    if (size > 0) {
3048f512ceSopenharmony_ci        buf_ = std::make_unique<uint8_t[]>(size);
3148f512ceSopenharmony_ci    }
3248f512ceSopenharmony_ci}
3348f512ceSopenharmony_ci
3448f512ceSopenharmony_ciRingBuffer::~RingBuffer() {}
3548f512ceSopenharmony_ci
3648f512ceSopenharmony_ci// get size of the writable space
3748f512ceSopenharmony_cisize_t RingBuffer::GetFreeSize() const
3848f512ceSopenharmony_ci{
3948f512ceSopenharmony_ci    return size_ - (head_.load(std::memory_order_relaxed) - tail_.load(std::memory_order_relaxed));
4048f512ceSopenharmony_ci}
4148f512ceSopenharmony_ci
4248f512ceSopenharmony_ciuint8_t *RingBuffer::AllocForWrite(size_t writeSize)
4348f512ceSopenharmony_ci{
4448f512ceSopenharmony_ci    if (buf_ == nullptr || buf_.get() == nullptr) {
4548f512ceSopenharmony_ci        return nullptr;
4648f512ceSopenharmony_ci    }
4748f512ceSopenharmony_ci    size_t writeHead = head_.load(std::memory_order_relaxed);
4848f512ceSopenharmony_ci    size_t readHead = tail_.load(std::memory_order_acquire);
4948f512ceSopenharmony_ci    if (size_ == 0) {
5048f512ceSopenharmony_ci        return nullptr;
5148f512ceSopenharmony_ci    }
5248f512ceSopenharmony_ci    size_t writePos = writeHead % size_;
5348f512ceSopenharmony_ci    size_t readPos = readHead % size_;
5448f512ceSopenharmony_ci    writeSize_ = writeSize;
5548f512ceSopenharmony_ci    if (writePos < readPos) {
5648f512ceSopenharmony_ci        // |---writePos<---writeSize--->readPos---|
5748f512ceSopenharmony_ci        if (writePos + writeSize > readPos) {
5848f512ceSopenharmony_ci            return nullptr;
5948f512ceSopenharmony_ci        }
6048f512ceSopenharmony_ci    } else if (writePos == readPos and writeHead != readHead) {
6148f512ceSopenharmony_ci        // writePos catch up with readPos, but buffer is full
6248f512ceSopenharmony_ci        return nullptr;
6348f512ceSopenharmony_ci    } else {
6448f512ceSopenharmony_ci        // two cases: 1, writePos catch up with readPos, but buffer is empty
6548f512ceSopenharmony_ci        //            2, |---readPos---writePos<---writeSize--->|
6648f512ceSopenharmony_ci        if (writePos + writeSize > size_) {
6748f512ceSopenharmony_ci            // no enough space at the end
6848f512ceSopenharmony_ci            if (readPos < writeSize) {
6948f512ceSopenharmony_ci                return nullptr;
7048f512ceSopenharmony_ci            }
7148f512ceSopenharmony_ci            // wrap to the start, set mark byte
7248f512ceSopenharmony_ci            buf_.get()[writePos] = MARGIN_BYTE;
7348f512ceSopenharmony_ci            writeSize_ += (size_ - writePos);
7448f512ceSopenharmony_ci            writePos = 0;
7548f512ceSopenharmony_ci        }
7648f512ceSopenharmony_ci    }
7748f512ceSopenharmony_ci
7848f512ceSopenharmony_ci    return buf_.get() + writePos;
7948f512ceSopenharmony_ci}
8048f512ceSopenharmony_ci
8148f512ceSopenharmony_civoid RingBuffer::EndWrite()
8248f512ceSopenharmony_ci{
8348f512ceSopenharmony_ci    size_t head = head_.load(std::memory_order_relaxed);
8448f512ceSopenharmony_ci    head += writeSize_;
8548f512ceSopenharmony_ci    head_.store(head, std::memory_order_release);
8648f512ceSopenharmony_ci}
8748f512ceSopenharmony_ci
8848f512ceSopenharmony_ciuint8_t *RingBuffer::GetReadData()
8948f512ceSopenharmony_ci{
9048f512ceSopenharmony_ci    CHECK_TRUE(buf_ == nullptr || buf_.get() == nullptr, nullptr, 0, "");
9148f512ceSopenharmony_ci    size_t writeHead = head_.load(std::memory_order_acquire);
9248f512ceSopenharmony_ci    size_t readHead = tail_.load(std::memory_order_relaxed);
9348f512ceSopenharmony_ci    if (writeHead == readHead) {
9448f512ceSopenharmony_ci        return nullptr;
9548f512ceSopenharmony_ci    }
9648f512ceSopenharmony_ci
9748f512ceSopenharmony_ci    readSize_ = 0;
9848f512ceSopenharmony_ci    if (size_ == 0) {
9948f512ceSopenharmony_ci        return nullptr;
10048f512ceSopenharmony_ci    }
10148f512ceSopenharmony_ci    size_t writePos = writeHead % size_;
10248f512ceSopenharmony_ci    size_t readPos = readHead % size_;
10348f512ceSopenharmony_ci    if (writePos <= readPos) {
10448f512ceSopenharmony_ci        // |<---data2--->writePos---readPos<---data1--->|
10548f512ceSopenharmony_ci        if (buf_.get()[readPos] == MARGIN_BYTE) {
10648f512ceSopenharmony_ci            CHECK_TRUE(writePos == 0, nullptr, 0, "");
10748f512ceSopenharmony_ci            readSize_ = (size_ - readPos);
10848f512ceSopenharmony_ci            readPos = 0;
10948f512ceSopenharmony_ci        }
11048f512ceSopenharmony_ci    }
11148f512ceSopenharmony_ci    // else |---readPos<---data--->writePos---|
11248f512ceSopenharmony_ci    perf_event_header *header = reinterpret_cast<perf_event_header *>(buf_.get() + readPos);
11348f512ceSopenharmony_ci    CHECK_TRUE(header == nullptr, nullptr, 0, "");
11448f512ceSopenharmony_ci
11548f512ceSopenharmony_ci    if (header->type == PERF_RECORD_AUXTRACE) {
11648f512ceSopenharmony_ci        struct PerfRecordAuxtraceData *auxtrace = reinterpret_cast<struct PerfRecordAuxtraceData *>(header + 1);
11748f512ceSopenharmony_ci        readSize_ += header->size + auxtrace->size;
11848f512ceSopenharmony_ci    } else {
11948f512ceSopenharmony_ci        readSize_ += header->size;
12048f512ceSopenharmony_ci    }
12148f512ceSopenharmony_ci    return buf_.get() + readPos;
12248f512ceSopenharmony_ci}
12348f512ceSopenharmony_ci
12448f512ceSopenharmony_civoid RingBuffer::EndRead()
12548f512ceSopenharmony_ci{
12648f512ceSopenharmony_ci    size_t tail = tail_.load(std::memory_order_relaxed);
12748f512ceSopenharmony_ci    tail += readSize_;
12848f512ceSopenharmony_ci    tail_.store(tail, std::memory_order_release);
12948f512ceSopenharmony_ci}
13048f512ceSopenharmony_ci} // namespace HiPerf
13148f512ceSopenharmony_ci} // namespace Developtools
13248f512ceSopenharmony_ci} // namespace OHOS
133