• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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