1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/util/trace_blob_view_reader.h"
18
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <optional>
24 #include <ostream>
25 #include <vector>
26
27 #include "perfetto/trace_processor/trace_blob.h"
28 #include "perfetto/trace_processor/trace_blob_view.h"
29 #include "test/gtest_and_gmock.h"
30
31 namespace perfetto::trace_processor::util {
32 namespace {
33
34 using ::testing::ElementsAreArray;
35 using ::testing::Eq;
36 using ::testing::Optional;
37 using ::testing::Property;
38 using ::testing::SizeIs;
39
40 class SameDataAsMatcher {
41 public:
42 template <typename ArgType>
43 class MatcherImpl : public ::testing ::MatcherInterface<const ArgType&> {
44 public:
MatcherImpl(const TraceBlobView & expected_data)45 explicit MatcherImpl(const TraceBlobView& expected_data)
46 : expected_data_(expected_data) {}
MatchAndExplain(const ArgType & arg,::testing::MatchResultListener *) const47 bool MatchAndExplain(const ArgType& arg,
48 ::testing ::MatchResultListener*) const override {
49 return std::equal(expected_data_.data(),
50 expected_data_.data() + expected_data_.size(),
51 arg.data(), arg.data() + arg.size());
52 }
DescribeTo(::std::ostream *) const53 void DescribeTo(::std ::ostream*) const override {}
DescribeNegationTo(::std::ostream *) const54 void DescribeNegationTo(::std ::ostream*) const override {}
55
56 private:
57 const TraceBlobView& expected_data_;
58 };
59
SameDataAsMatcher(const TraceBlobView & expected_data)60 explicit SameDataAsMatcher(const TraceBlobView& expected_data)
61 : expected_data_(expected_data) {}
62
63 template <typename ArgType>
operator ::testing::Matcher<ArgType>() const64 operator ::testing::Matcher<ArgType>() const {
65 return ::testing::Matcher<ArgType>(
66 new MatcherImpl<ArgType>(expected_data_));
67 }
68
69 private:
70 const TraceBlobView& expected_data_;
71 };
72
SameDataAs(const TraceBlobView & expected_data)73 SameDataAsMatcher SameDataAs(const TraceBlobView& expected_data) {
74 return SameDataAsMatcher(expected_data);
75 }
76
CreateExpectedData(size_t expected_size)77 TraceBlobView CreateExpectedData(size_t expected_size) {
78 TraceBlob tb = TraceBlob::Allocate(expected_size);
79 for (size_t i = 0; i < expected_size; ++i) {
80 tb.data()[i] = static_cast<uint8_t>(i);
81 }
82 return TraceBlobView(std::move(tb));
83 }
84
Slice(const TraceBlobView & blob,size_t chunk_size)85 std::vector<TraceBlobView> Slice(const TraceBlobView& blob, size_t chunk_size) {
86 std::vector<TraceBlobView> chunks;
87 size_t size = blob.size();
88 for (size_t off = 0; size != 0;) {
89 chunk_size = std::min(chunk_size, size);
90 chunks.push_back(blob.slice_off(off, chunk_size));
91 size -= chunk_size;
92 off += chunk_size;
93 }
94 return chunks;
95 }
96
CreateTraceBlobViewReader(const std::vector<TraceBlobView> & chunks)97 TraceBlobViewReader CreateTraceBlobViewReader(
98 const std::vector<TraceBlobView>& chunks) {
99 TraceBlobViewReader chunked_buffer;
100 for (const auto& chunk : chunks) {
101 chunked_buffer.PushBack(chunk.copy());
102 }
103 return chunked_buffer;
104 }
105
TEST(TraceBlobViewReader,ContiguousAccessAtOffset)106 TEST(TraceBlobViewReader, ContiguousAccessAtOffset) {
107 constexpr size_t kExpectedSize = 256;
108 constexpr size_t kChunkSize = kExpectedSize / 4;
109 TraceBlobView expected_data = CreateExpectedData(kExpectedSize);
110 TraceBlobViewReader buffer =
111 CreateTraceBlobViewReader(Slice(expected_data, kChunkSize));
112
113 for (size_t file_offset = 0; file_offset <= kExpectedSize; ++file_offset) {
114 EXPECT_TRUE(buffer.PopFrontUntil(file_offset));
115 for (size_t off = file_offset; off <= kExpectedSize; ++off) {
116 auto expected = expected_data.slice_off(off, kExpectedSize - off);
117 std::optional<TraceBlobView> tbv = buffer.SliceOff(off, expected.size());
118 EXPECT_THAT(tbv, Optional(SameDataAs(expected)));
119 }
120 }
121 }
122
TEST(TraceBlobViewReader,NoCopyIfDataIsContiguous)123 TEST(TraceBlobViewReader, NoCopyIfDataIsContiguous) {
124 constexpr size_t kExpectedSize = 256;
125 constexpr size_t kChunkSize = kExpectedSize / 4;
126 std::vector<TraceBlobView> chunks =
127 Slice(CreateExpectedData(kExpectedSize), kChunkSize);
128 TraceBlobViewReader buffer = CreateTraceBlobViewReader(chunks);
129
130 for (size_t i = 0; i < chunks.size(); ++i) {
131 for (size_t off = 0; off < kChunkSize; ++off) {
132 const size_t expected_size = kChunkSize - off;
133 EXPECT_THAT(
134 buffer.SliceOff(i * kChunkSize + off, expected_size),
135 Optional(Property(&TraceBlobView::data, Eq(chunks[i].data() + off))));
136 }
137 }
138 }
139
TEST(TraceBlobViewReader,PopRemovesData)140 TEST(TraceBlobViewReader, PopRemovesData) {
141 size_t expected_size = 256;
142 size_t expected_file_offset = 0;
143 const size_t kChunkSize = expected_size / 4;
144 TraceBlobView expected_data = CreateExpectedData(expected_size);
145 TraceBlobViewReader buffer =
146 CreateTraceBlobViewReader(Slice(expected_data, kChunkSize));
147
148 --expected_size;
149 ++expected_file_offset;
150 buffer.PopFrontUntil(expected_file_offset);
151 EXPECT_THAT(buffer.start_offset(), Eq(expected_file_offset));
152 EXPECT_THAT(buffer.SliceOff(expected_file_offset, expected_size),
153 Optional(SameDataAs(expected_data.slice_off(
154 expected_data.size() - expected_size, expected_size))));
155
156 expected_size -= kChunkSize;
157 expected_file_offset += kChunkSize;
158 buffer.PopFrontUntil(expected_file_offset);
159 EXPECT_THAT(buffer.start_offset(), Eq(expected_file_offset));
160 EXPECT_THAT(buffer.SliceOff(expected_file_offset, expected_size),
161 Optional(SameDataAs(expected_data.slice_off(
162 expected_data.size() - expected_size, expected_size))));
163 }
164
165 } // namespace
166 } // namespace perfetto::trace_processor::util
167