/* * 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. */ #ifndef SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_ #define SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_ #include #include #include "perfetto/ext/base/circular_queue.h" #include "perfetto/trace_processor/trace_blob_view.h" namespace perfetto::trace_processor::util { // Helper class that exposes a window into the contents of a file. Data can be // appended to the end of the buffer (increasing the size of the window) or // removed from the front (decreasing the size of the window). // // TraceProcessor reads trace files in chunks and streams those to the // `ChunkedTraceReader` instance. But sometimes the reader needs to look into // the future (i.e. some data that has not yet arrived) before being able to // process the current data. In such a case the reader would have to buffer data // until the "future" data arrives. This class encapsulates that functionality. class FileBuffer { public: // Trivial empty ctor. FileBuffer() = default; bool empty() const { return data_.empty(); } // Returns the offset to the start of the buffered window of data. size_t file_offset() const { return data_.empty() ? end_offset_ : data_.front().file_offset; } // Adds a `TraceBlobView` at the back. void PushBack(TraceBlobView view); // Shrinks the buffer by dropping data from the front of the buffer until the // given offset is reached. If not enough data is present as much data as // possible will be dropped and `false` will be returned. // ATTENTION: If `offset` < 'file_offset()' (i.e. you try to access data // previously popped) this method will CHECK fail. bool PopFrontUntil(size_t offset); // Shrinks the buffer by dropping `bytes` from the front of the buffer. If not // enough data is present as much data as possible will be dropped and `false` // will be returned. bool PopFrontBytes(size_t bytes) { return PopFrontUntil(file_offset() + bytes); } // Similar to `TraceBlobView::slice_off`, creates a slice with data starting // at `offset` and of the given `length`. This method might need to allocate a // new buffer and copy data into it (if the requested data spans multiple // TraceBlobView instances). If not enough data is present `std::nullopt` is // returned. // // ATTENTION: If `offset` < 'file_offset()' (i.e. you try to access data // previously popped) this method will CHECK fail. std::optional SliceOff(size_t offset, size_t length) const; private: struct Entry { // File offset of the first byte in `data`. size_t file_offset; TraceBlobView data; }; using Iterator = base::CircularQueue::Iterator; // Finds the `TraceBlobView` at `offset` and returns a slice starting at that // offset and spanning the rest of the `TraceBlobView`. It also returns an // iterator to the next `TraceBlobView` instance (which might be `end()`). Iterator FindEntryWithOffset(size_t offset) const; Iterator end() const { return data_.end(); } // CircularQueue has no const_iterator, so mutable is needed to access it from // const methods. // CircularQueue has no const_iterator, so mutable is needed to access it from // const methods. mutable base::CircularQueue data_; size_t end_offset_ = 0; }; } // namespace perfetto::trace_processor::util #endif // SRC_TRACE_PROCESSOR_UTIL_FILE_BUFFER_H_