1
2 /*
3 * Copyright (C) 2024 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "src/trace_processor/util/file_buffer.h"
19
20 #include <algorithm>
21 #include <cstddef>
22 #include <cstdint>
23 #include <cstring>
24 #include <iterator>
25 #include <optional>
26
27 #include "perfetto/base/logging.h"
28 #include "perfetto/trace_processor/trace_blob.h"
29 #include "perfetto/trace_processor/trace_blob_view.h"
30
31 namespace perfetto::trace_processor::util {
32
PushBack(TraceBlobView data)33 void FileBuffer::PushBack(TraceBlobView data) {
34 if (data.size() == 0) {
35 return;
36 }
37 const size_t size = data.size();
38 data_.emplace_back(Entry{end_offset_, std::move(data)});
39 end_offset_ += size;
40 }
41
PopFrontUntil(const size_t target_offset)42 bool FileBuffer::PopFrontUntil(const size_t target_offset) {
43 PERFETTO_CHECK(file_offset() <= target_offset);
44 while (!data_.empty()) {
45 Entry& entry = data_.front();
46 if (target_offset == entry.file_offset) {
47 return true;
48 }
49 const size_t bytes_to_pop = target_offset - entry.file_offset;
50 if (entry.data.size() > bytes_to_pop) {
51 entry.data =
52 entry.data.slice_off(bytes_to_pop, entry.data.size() - bytes_to_pop);
53 entry.file_offset += bytes_to_pop;
54 return true;
55 }
56 data_.pop_front();
57 }
58
59 return target_offset == end_offset_;
60 }
61
SliceOff(size_t start_offset,size_t length) const62 std::optional<TraceBlobView> FileBuffer::SliceOff(size_t start_offset,
63 size_t length) const {
64 if (length == 0) {
65 return TraceBlobView();
66 }
67
68 if (start_offset + length > end_offset_) {
69 return std::nullopt;
70 }
71
72 Iterator it = FindEntryWithOffset(start_offset);
73 if (it == end()) {
74 return std::nullopt;
75 }
76
77 const size_t offset_from_entry_start = start_offset - it->file_offset;
78 const size_t bytes_in_entry = it->data.size() - offset_from_entry_start;
79 TraceBlobView first_blob = it->data.slice_off(
80 offset_from_entry_start, std::min(bytes_in_entry, length));
81
82 if (first_blob.size() == length) {
83 return std::move(first_blob);
84 }
85
86 auto buffer = TraceBlob::Allocate(length);
87 uint8_t* ptr = buffer.data();
88
89 memcpy(ptr, first_blob.data(), first_blob.size());
90 ptr += first_blob.size();
91 length -= first_blob.size();
92 ++it;
93
94 while (length != 0) {
95 PERFETTO_DCHECK(it != end());
96 const size_t bytes_to_copy = std::min(length, it->data.size());
97 memcpy(ptr, it->data.data(), bytes_to_copy);
98 ptr += bytes_to_copy;
99 length -= bytes_to_copy;
100 ++it;
101 }
102
103 return TraceBlobView(std::move(buffer));
104 }
105
FindEntryWithOffset(size_t offset) const106 FileBuffer::Iterator FileBuffer::FindEntryWithOffset(size_t offset) const {
107 if (offset >= end_offset_) {
108 return end();
109 }
110
111 auto it = std::upper_bound(
112 data_.begin(), data_.end(), offset,
113 [](size_t offset, const Entry& rhs) { return offset < rhs.file_offset; });
114 // This can only happen if too much data was popped.
115 PERFETTO_CHECK(it != data_.begin());
116 return std::prev(it);
117 }
118
119 } // namespace perfetto::trace_processor::util
120