/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/trace_processor/util/file_buffer.h" #include #include #include #include #include #include #include "perfetto/base/logging.h" #include "perfetto/trace_processor/trace_blob.h" #include "perfetto/trace_processor/trace_blob_view.h" namespace perfetto::trace_processor::util { void FileBuffer::PushBack(TraceBlobView data) { if (data.size() == 0) { return; } const size_t size = data.size(); data_.emplace_back(Entry{end_offset_, std::move(data)}); end_offset_ += size; } bool FileBuffer::PopFrontUntil(const size_t target_offset) { PERFETTO_CHECK(file_offset() <= target_offset); while (!data_.empty()) { Entry& entry = data_.front(); if (target_offset == entry.file_offset) { return true; } const size_t bytes_to_pop = target_offset - entry.file_offset; if (entry.data.size() > bytes_to_pop) { entry.data = entry.data.slice_off(bytes_to_pop, entry.data.size() - bytes_to_pop); entry.file_offset += bytes_to_pop; return true; } data_.pop_front(); } return target_offset == end_offset_; } std::optional FileBuffer::SliceOff(size_t start_offset, size_t length) const { if (length == 0) { return TraceBlobView(); } if (start_offset + length > end_offset_) { return std::nullopt; } Iterator it = FindEntryWithOffset(start_offset); if (it == end()) { return std::nullopt; } const size_t offset_from_entry_start = start_offset - it->file_offset; const size_t bytes_in_entry = it->data.size() - offset_from_entry_start; TraceBlobView first_blob = it->data.slice_off( offset_from_entry_start, std::min(bytes_in_entry, length)); if (first_blob.size() == length) { return std::move(first_blob); } auto buffer = TraceBlob::Allocate(length); uint8_t* ptr = buffer.data(); memcpy(ptr, first_blob.data(), first_blob.size()); ptr += first_blob.size(); length -= first_blob.size(); ++it; while (length != 0) { PERFETTO_DCHECK(it != end()); const size_t bytes_to_copy = std::min(length, it->data.size()); memcpy(ptr, it->data.data(), bytes_to_copy); ptr += bytes_to_copy; length -= bytes_to_copy; ++it; } return TraceBlobView(std::move(buffer)); } FileBuffer::Iterator FileBuffer::FindEntryWithOffset(size_t offset) const { if (offset >= end_offset_) { return end(); } auto it = std::upper_bound( data_.begin(), data_.end(), offset, [](size_t offset, const Entry& rhs) { return offset < rhs.file_offset; }); // This can only happen if too much data was popped. PERFETTO_CHECK(it != data_.begin()); return std::prev(it); } } // namespace perfetto::trace_processor::util