• 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/trace_processor/importers/gzip/gzip_trace_parser.h"
18 
19 #include <string>
20 
21 #include "perfetto/base/logging.h"
22 #include "perfetto/ext/base/string_utils.h"
23 #include "perfetto/ext/base/string_view.h"
24 #include "src/trace_processor/forwarding_trace_parser.h"
25 #include "src/trace_processor/util/status_macros.h"
26 
27 namespace perfetto {
28 namespace trace_processor {
29 
30 namespace {
31 
32 using ResultCode = GzipDecompressor::ResultCode;
33 
34 }  // namespace
35 
GzipTraceParser(TraceProcessorContext * context)36 GzipTraceParser::GzipTraceParser(TraceProcessorContext* context)
37     : context_(context) {}
38 
GzipTraceParser(std::unique_ptr<ChunkedTraceReader> reader)39 GzipTraceParser::GzipTraceParser(std::unique_ptr<ChunkedTraceReader> reader)
40     : context_(nullptr), inner_(std::move(reader)) {}
41 
42 GzipTraceParser::~GzipTraceParser() = default;
43 
Parse(std::unique_ptr<uint8_t[]> data,size_t size)44 util::Status GzipTraceParser::Parse(std::unique_ptr<uint8_t[]> data,
45                                     size_t size) {
46   return ParseUnowned(data.get(), size);
47 }
48 
ParseUnowned(const uint8_t * data,size_t size)49 util::Status GzipTraceParser::ParseUnowned(const uint8_t* data, size_t size) {
50   const uint8_t* start = data;
51   size_t len = size;
52 
53   if (!inner_) {
54     PERFETTO_CHECK(context_);
55     inner_.reset(new ForwardingTraceParser(context_));
56   }
57 
58   if (!first_chunk_parsed_) {
59     // .ctrace files begin with: "TRACE:\n" or "done. TRACE:\n" strip this if
60     // present.
61     base::StringView beginning(reinterpret_cast<const char*>(start), size);
62 
63     static const char* kSystraceFileHeader = "TRACE:\n";
64     size_t offset = Find(kSystraceFileHeader, beginning);
65     if (offset != std::string::npos) {
66       start += strlen(kSystraceFileHeader) + offset;
67       len -= strlen(kSystraceFileHeader) + offset;
68     }
69     first_chunk_parsed_ = true;
70   }
71 
72   // Our default uncompressed buffer size is 32MB as it allows for good
73   // throughput.
74   constexpr size_t kUncompressedBufferSize = 32 * 1024 * 1024;
75 
76   needs_more_input_ = false;
77   decompressor_.SetInput(start, len);
78 
79   for (auto ret = ResultCode::kOk; ret != ResultCode::kEof;) {
80     if (!buffer_) {
81       buffer_.reset(new uint8_t[kUncompressedBufferSize]);
82       bytes_written_ = 0;
83     }
84 
85     auto result =
86         decompressor_.Decompress(buffer_.get() + bytes_written_,
87                                  kUncompressedBufferSize - bytes_written_);
88     ret = result.ret;
89     if (ret == ResultCode::kError || ret == ResultCode::kNoProgress)
90       return util::ErrStatus("Failed to decompress trace chunk");
91 
92     if (ret == ResultCode::kNeedsMoreInput) {
93       PERFETTO_DCHECK(result.bytes_written == 0);
94       needs_more_input_ = true;
95       return util::OkStatus();
96     }
97     bytes_written_ += result.bytes_written;
98 
99     if (bytes_written_ == kUncompressedBufferSize || ret == ResultCode::kEof)
100       RETURN_IF_ERROR(inner_->Parse(std::move(buffer_), bytes_written_));
101   }
102   return util::OkStatus();
103 }
104 
NotifyEndOfFile()105 void GzipTraceParser::NotifyEndOfFile() {
106   // TODO(lalitm): this should really be an error returned to the caller but
107   // due to historical implementation, NotifyEndOfFile does not return a
108   // util::Status.
109   PERFETTO_DCHECK(!needs_more_input_);
110   PERFETTO_DCHECK(!buffer_);
111 }
112 
113 }  // namespace trace_processor
114 }  // namespace perfetto
115