• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/file_buffer.h"
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <vector>
24 
25 #include "perfetto/trace_processor/trace_blob.h"
26 #include "perfetto/trace_processor/trace_blob_view.h"
27 #include "test/gtest_and_gmock.h"
28 
29 namespace perfetto::trace_processor::util {
30 namespace {
31 
32 using ::testing::ElementsAreArray;
33 using ::testing::Eq;
34 using ::testing::Optional;
35 using ::testing::Property;
36 using ::testing::SizeIs;
37 
38 class SameDataAsMatcher {
39  public:
40   template <typename ArgType>
41   class MatcherImpl : public ::testing ::MatcherInterface<const ArgType&> {
42    public:
MatcherImpl(const TraceBlobView & expected_data)43     explicit MatcherImpl(const TraceBlobView& expected_data)
44         : expected_data_(expected_data) {}
MatchAndExplain(const ArgType & arg,::testing::MatchResultListener *) const45     bool MatchAndExplain(const ArgType& arg,
46                          ::testing ::MatchResultListener*) const override {
47       return std::equal(expected_data_.data(),
48                         expected_data_.data() + expected_data_.size(),
49                         arg.data(), arg.data() + arg.size());
50     }
DescribeTo(::std::ostream *) const51     void DescribeTo(::std ::ostream*) const override {}
DescribeNegationTo(::std::ostream *) const52     void DescribeNegationTo(::std ::ostream*) const override {}
53 
54    private:
55     const TraceBlobView& expected_data_;
56   };
57 
SameDataAsMatcher(const TraceBlobView & expected_data)58   explicit SameDataAsMatcher(const TraceBlobView& expected_data)
59       : expected_data_(expected_data) {}
60 
61   template <typename ArgType>
operator ::testing::Matcher<ArgType>() const62   operator ::testing::Matcher<ArgType>() const {
63     return ::testing::Matcher<ArgType>(
64         new MatcherImpl<ArgType>(expected_data_));
65   }
66 
67  private:
68   const TraceBlobView& expected_data_;
69 };
70 
SameDataAs(const TraceBlobView & expected_data)71 SameDataAsMatcher SameDataAs(const TraceBlobView& expected_data) {
72   return SameDataAsMatcher(expected_data);
73 }
74 
CreateExpectedData(size_t expected_size)75 TraceBlobView CreateExpectedData(size_t expected_size) {
76   TraceBlob tb = TraceBlob::Allocate(expected_size);
77   for (size_t i = 0; i < expected_size; ++i) {
78     tb.data()[i] = static_cast<uint8_t>(i);
79   }
80   return TraceBlobView(std::move(tb));
81 }
82 
Slice(const TraceBlobView & blob,size_t chunk_size)83 std::vector<TraceBlobView> Slice(const TraceBlobView& blob, size_t chunk_size) {
84   std::vector<TraceBlobView> chunks;
85   size_t size = blob.size();
86   for (size_t off = 0; size != 0;) {
87     chunk_size = std::min(chunk_size, size);
88     chunks.push_back(blob.slice_off(off, chunk_size));
89     size -= chunk_size;
90     off += chunk_size;
91   }
92   return chunks;
93 }
94 
CreateFileBuffer(const std::vector<TraceBlobView> & chunks)95 FileBuffer CreateFileBuffer(const std::vector<TraceBlobView>& chunks) {
96   FileBuffer chunked_buffer;
97   for (const auto& chunk : chunks) {
98     chunked_buffer.PushBack(chunk.copy());
99   }
100   return chunked_buffer;
101 }
102 
TEST(FileBuffer,ContiguousAccessAtOffset)103 TEST(FileBuffer, ContiguousAccessAtOffset) {
104   constexpr size_t kExpectedSize = 256;
105   constexpr size_t kChunkSize = kExpectedSize / 4;
106   TraceBlobView expected_data = CreateExpectedData(kExpectedSize);
107   FileBuffer buffer = CreateFileBuffer(Slice(expected_data, kChunkSize));
108 
109   for (size_t file_offset = 0; file_offset <= kExpectedSize; ++file_offset) {
110     EXPECT_TRUE(buffer.PopFrontUntil(file_offset));
111     for (size_t off = file_offset; off <= kExpectedSize; ++off) {
112       auto expected = expected_data.slice_off(off, kExpectedSize - off);
113       std::optional<TraceBlobView> tbv = buffer.SliceOff(off, expected.size());
114       EXPECT_THAT(tbv, Optional(SameDataAs(expected)));
115     }
116   }
117 }
118 
TEST(FileBuffer,NoCopyIfDataIsContiguous)119 TEST(FileBuffer, NoCopyIfDataIsContiguous) {
120   constexpr size_t kExpectedSize = 256;
121   constexpr size_t kChunkSize = kExpectedSize / 4;
122   std::vector<TraceBlobView> chunks =
123       Slice(CreateExpectedData(kExpectedSize), kChunkSize);
124   FileBuffer buffer = CreateFileBuffer(chunks);
125 
126   for (size_t i = 0; i < chunks.size(); ++i) {
127     for (size_t off = 0; off < kChunkSize; ++off) {
128       const size_t expected_size = kChunkSize - off;
129       EXPECT_THAT(
130           buffer.SliceOff(i * kChunkSize + off, expected_size),
131           Optional(Property(&TraceBlobView::data, Eq(chunks[i].data() + off))));
132     }
133   }
134 }
135 
TEST(FileBuffer,PopRemovesData)136 TEST(FileBuffer, PopRemovesData) {
137   size_t expected_size = 256;
138   size_t expected_file_offset = 0;
139   const size_t kChunkSize = expected_size / 4;
140   TraceBlobView expected_data = CreateExpectedData(expected_size);
141   FileBuffer buffer = CreateFileBuffer(Slice(expected_data, kChunkSize));
142 
143   --expected_size;
144   ++expected_file_offset;
145   buffer.PopFrontUntil(expected_file_offset);
146   EXPECT_THAT(buffer.file_offset(), Eq(expected_file_offset));
147   EXPECT_THAT(buffer.SliceOff(expected_file_offset, expected_size),
148               Optional(SameDataAs(expected_data.slice_off(
149                   expected_data.size() - expected_size, expected_size))));
150 
151   expected_size -= kChunkSize;
152   expected_file_offset += kChunkSize;
153   buffer.PopFrontUntil(expected_file_offset);
154   EXPECT_THAT(buffer.file_offset(), Eq(expected_file_offset));
155   EXPECT_THAT(buffer.SliceOff(expected_file_offset, expected_size),
156               Optional(SameDataAs(expected_data.slice_off(
157                   expected_data.size() - expected_size, expected_size))));
158 }
159 
160 }  // namespace
161 }  // namespace perfetto::trace_processor::util
162