• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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/perfetto_cmd/packet_writer.h"
18 
19 #include <string.h>
20 #include <unistd.h>
21 
22 #include <random>
23 
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 #include <zlib.h>
27 
28 #include "perfetto/base/file_utils.h"
29 #include "perfetto/base/scoped_file.h"
30 #include "perfetto/base/temp_file.h"
31 #include "perfetto/tracing/core/trace_packet.h"
32 #include "perfetto/protozero/scattered_heap_buffer.h"
33 #include "perfetto/trace/test_event.pbzero.h"
34 #include "perfetto/trace/trace.pb.h"
35 #include "perfetto/trace/trace_packet.pb.h"
36 #include "perfetto/trace/trace_packet.pbzero.h"
37 #include "src/perfetto_cmd/packet_writer.h"
38 
39 namespace perfetto {
40 namespace {
41 
42 using TracePacketZero = protos::pbzero::TracePacket;
43 
44 template <typename F>
CreateTracePacket(F fill_function)45 TracePacket CreateTracePacket(F fill_function) {
46   protozero::HeapBuffered<TracePacketZero> msg;
47   fill_function(msg.get());
48   msg->Finalize();
49   std::vector<uint8_t> buf = msg.SerializeAsArray();
50   Slice slice = Slice::Allocate(buf.size());
51   memcpy(slice.own_data(), buf.data(), buf.size());
52   perfetto::TracePacket packet;
53   packet.AddSlice(std::move(slice));
54   return packet;
55 }
56 
Decompress(const std::string & data)57 std::string Decompress(const std::string& data) {
58   uint8_t out[1024];
59 
60   z_stream stream{};
61   stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
62   stream.avail_in = static_cast<unsigned int>(data.size());
63 
64   EXPECT_EQ(inflateInit(&stream), Z_OK);
65   std::string s;
66 
67   int ret;
68   do {
69     stream.next_out = out;
70     stream.avail_out = sizeof(out);
71     ret = inflate(&stream, Z_NO_FLUSH);
72     EXPECT_NE(ret, Z_STREAM_ERROR);
73     EXPECT_NE(ret, Z_NEED_DICT);
74     EXPECT_NE(ret, Z_DATA_ERROR);
75     EXPECT_NE(ret, Z_MEM_ERROR);
76     s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
77   } while (ret != Z_STREAM_END);
78 
79   inflateEnd(&stream);
80   return s;
81 }
82 
TEST(PacketWriter,FilePacketWriter)83 TEST(PacketWriter, FilePacketWriter) {
84   base::TempFile tmp = base::TempFile::Create();
85   FILE* f = fdopen(tmp.fd(), "wb");
86 
87   {
88     std::unique_ptr<PacketWriter> writer = CreateFilePacketWriter(f);
89 
90     std::vector<perfetto::TracePacket> packets;
91 
92     packets.push_back(CreateTracePacket([](TracePacketZero* msg) {
93       auto* for_testing = msg->set_for_testing();
94       for_testing->set_str("abc");
95     }));
96 
97     EXPECT_TRUE(writer->WritePackets(std::move(packets)));
98   }
99 
100   fseek(f, 0, SEEK_SET);
101   std::string s;
102   EXPECT_TRUE(base::ReadFileStream(f, &s));
103   EXPECT_GT(s.size(), 0);
104 
105   protos::Trace trace;
106   EXPECT_TRUE(trace.ParseFromString(s));
107   EXPECT_EQ(trace.packet().Get(0).for_testing().str(), "abc");
108 }
109 
TEST(PacketWriter,ZipPacketWriter)110 TEST(PacketWriter, ZipPacketWriter) {
111   base::TempFile tmp = base::TempFile::Create();
112   FILE* f = fdopen(tmp.fd(), "wb");
113 
114   {
115     std::unique_ptr<PacketWriter> writer =
116         CreateZipPacketWriter(CreateFilePacketWriter(f));
117 
118     std::vector<perfetto::TracePacket> packets;
119 
120     packets.push_back(CreateTracePacket([](TracePacketZero* msg) {
121       auto* for_testing = msg->set_for_testing();
122       for_testing->set_str("abc");
123     }));
124 
125     EXPECT_TRUE(writer->WritePackets(std::move(packets)));
126   }
127 
128   std::string s;
129   fseek(f, 0, SEEK_SET);
130   EXPECT_TRUE(base::ReadFileStream(f, &s));
131   EXPECT_GT(s.size(), 0);
132 
133   protos::Trace trace;
134   EXPECT_TRUE(trace.ParseFromString(s));
135 
136   const std::string& data = trace.packet().Get(0).compressed_packets();
137   EXPECT_GT(data.size(), 0);
138 
139   protos::Trace subtrace;
140   EXPECT_TRUE(subtrace.ParseFromString(Decompress(data)));
141   EXPECT_EQ(subtrace.packet().Get(0).for_testing().str(), "abc");
142 }
143 
TEST(PacketWriter,ZipPacketWriter_Empty)144 TEST(PacketWriter, ZipPacketWriter_Empty) {
145   base::TempFile tmp = base::TempFile::Create();
146   FILE* f = fdopen(tmp.fd(), "wb");
147 
148   {
149     std::unique_ptr<PacketWriter> writer =
150         CreateZipPacketWriter(CreateFilePacketWriter(f));
151   }
152 
153   EXPECT_EQ(fseek(f, 0, SEEK_END), 0);
154 }
155 
TEST(PacketWriter,ZipPacketWriter_EmptyWithEmptyWrite)156 TEST(PacketWriter, ZipPacketWriter_EmptyWithEmptyWrite) {
157   base::TempFile tmp = base::TempFile::Create();
158   FILE* f = fdopen(tmp.fd(), "wb");
159 
160   {
161     std::unique_ptr<PacketWriter> writer =
162         CreateZipPacketWriter(CreateFilePacketWriter(f));
163     writer->WritePackets(std::vector<TracePacket>());
164     writer->WritePackets(std::vector<TracePacket>());
165     writer->WritePackets(std::vector<TracePacket>());
166   }
167 
168   EXPECT_EQ(fseek(f, 0, SEEK_END), 0);
169 }
170 
TEST(PacketWriter,ZipPacketWriter_ShouldCompress)171 TEST(PacketWriter, ZipPacketWriter_ShouldCompress) {
172   base::TempFile tmp = base::TempFile::Create();
173   FILE* f = fdopen(tmp.fd(), "wb");
174   size_t uncompressed_size = 0;
175 
176   {
177     std::unique_ptr<PacketWriter> writer =
178         CreateZipPacketWriter(CreateFilePacketWriter(f));
179 
180     for (size_t i = 0; i < 200; i++) {
181       std::vector<perfetto::TracePacket> packets;
182 
183       packets.push_back(CreateTracePacket([](TracePacketZero* msg) {
184         auto* for_testing = msg->set_for_testing();
185         for_testing->set_str("abcdefghijklmn");
186       }));
187 
188       packets.push_back(CreateTracePacket([](TracePacketZero* msg) {
189         auto* for_testing = msg->set_for_testing();
190         for_testing->set_str("abcdefghijklmn");
191       }));
192 
193       for (const TracePacket& packet : packets)
194         uncompressed_size += packet.size();
195 
196       EXPECT_TRUE(writer->WritePackets(std::move(packets)));
197     }
198   }
199 
200   std::string s;
201   EXPECT_LT(fseek(f, 0, SEEK_END), uncompressed_size);
202   fseek(f, 0, SEEK_SET);
203   EXPECT_TRUE(base::ReadFileStream(f, &s));
204   EXPECT_GT(s.size(), 0);
205 
206   protos::Trace trace;
207   EXPECT_TRUE(trace.ParseFromString(s));
208 
209   size_t packet_count = 0;
210   for (const auto& packet : trace.packet()) {
211     const std::string& data = packet.compressed_packets();
212     EXPECT_GT(data.size(), 0);
213     EXPECT_LT(data.size(), 500 * 1024);
214     protos::Trace subtrace;
215     EXPECT_TRUE(subtrace.ParseFromString(Decompress(data)));
216     for (const auto& subpacket : subtrace.packet()) {
217       packet_count++;
218       EXPECT_EQ(subpacket.for_testing().str(), "abcdefghijklmn");
219     }
220   }
221 
222   EXPECT_EQ(packet_count, 200 * 2);
223 }
224 
TEST(PacketWriter,ZipPacketWriter_ShouldSplitPackets)225 TEST(PacketWriter, ZipPacketWriter_ShouldSplitPackets) {
226   base::TempFile tmp = base::TempFile::Create();
227   FILE* f = fdopen(tmp.fd(), "wb");
228 
229   std::minstd_rand0 rnd(0);
230   std::uniform_int_distribution<> dist(0, 255);
231   auto randomString = [&dist, &rnd]() {
232     std::string s;
233     s.resize(1024);
234     for (size_t i = 0; i < s.size(); i++)
235       s[i] = static_cast<char>(dist(rnd));
236     return s;
237   };
238 
239   {
240     std::unique_ptr<PacketWriter> writer =
241         CreateZipPacketWriter(CreateFilePacketWriter(f));
242 
243     for (uint32_t i = 0; i < 1000; i++) {
244       std::vector<perfetto::TracePacket> packets;
245 
246       std::string s = randomString();
247 
248       packets.push_back(CreateTracePacket([i, &s](TracePacketZero* msg) {
249         auto* for_testing = msg->set_for_testing();
250         for_testing->set_seq_value(i);
251         for_testing->set_str(s.data(), s.size());
252       }));
253 
254       EXPECT_TRUE(writer->WritePackets(std::move(packets)));
255     }
256   }
257 
258   std::string s;
259   fseek(f, 0, SEEK_SET);
260   EXPECT_TRUE(base::ReadFileStream(f, &s));
261   EXPECT_GT(s.size(), 0);
262 
263   protos::Trace trace;
264   EXPECT_TRUE(trace.ParseFromString(s));
265 
266   size_t packet_count = 0;
267   for (const auto& packet : trace.packet()) {
268     const std::string& data = packet.compressed_packets();
269     EXPECT_GT(data.size(), 0);
270     EXPECT_LT(data.size(), 500 * 1024);
271     protos::Trace subtrace;
272     EXPECT_TRUE(subtrace.ParseFromString(Decompress(data)));
273     for (const auto& subpacket : subtrace.packet()) {
274       EXPECT_EQ(subpacket.for_testing().seq_value(), packet_count++);
275     }
276   }
277 
278   EXPECT_EQ(packet_count, 1000);
279 }
280 
281 }  // namespace
282 }  // namespace perfetto
283