blob: 129f5510e253ea1cf4832fc12a1c05d47a1c5a9a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// For bazel build.
#include "perfetto/base/build_config.h"
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
#include "src/trace_processor/gzip_trace_parser.h"
#include <string>
#include <zlib.h>
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/forwarding_trace_parser.h"
namespace perfetto {
namespace trace_processor {
GzipTraceParser::GzipTraceParser(TraceProcessorContext* context)
: context_(context), z_stream_(new z_stream()) {
z_stream_->zalloc = Z_NULL;
z_stream_->zfree = Z_NULL;
z_stream_->opaque = Z_NULL;
inflateInit2(z_stream_.get(), 32 + 15);
}
GzipTraceParser::~GzipTraceParser() {
// Ensure the call to inflateEnd to prevent leaks of internal state.
inflateEnd(z_stream_.get());
}
util::Status GzipTraceParser::Parse(std::unique_ptr<uint8_t[]> data,
size_t size) {
uint8_t* start = data.get();
size_t len = size;
if (!inner_) {
inner_.reset(new ForwardingTraceParser(context_));
// .ctrace files begin with: "TRACE:\n" or "done. TRACE:\n" strip this if
// present.
base::StringView beginning(reinterpret_cast<char*>(start), size);
static const char* kSystraceFileHeader = "TRACE:\n";
size_t offset = Find(kSystraceFileHeader, beginning);
if (offset != std::string::npos) {
start += strlen(kSystraceFileHeader) + offset;
len -= strlen(kSystraceFileHeader) + offset;
}
}
z_stream_->next_in = start;
z_stream_->avail_in = static_cast<uInt>(len);
// Our default uncompressed buffer size is 32MB as it allows for good
// throughput.
constexpr size_t kUncompressedBufferSize = 32 * 1024 * 1024;
int ret = Z_OK;
for (; ret != Z_STREAM_END && z_stream_->avail_in != 0;) {
std::unique_ptr<uint8_t[]> buffer(new uint8_t[kUncompressedBufferSize]);
z_stream_->next_out = buffer.get();
z_stream_->avail_out = static_cast<uInt>(kUncompressedBufferSize);
ret = inflate(z_stream_.get(), Z_NO_FLUSH);
switch (ret) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
// Ignore inflateEnd error as we will error out anyway.
inflateEnd(z_stream_.get());
return util::ErrStatus("Error decompressing ctrace file");
}
size_t read = kUncompressedBufferSize - z_stream_->avail_out;
util::Status status = inner_->Parse(std::move(buffer), read);
if (!status.ok())
return status;
}
if (ret == Z_STREAM_END) {
ret = inflateEnd(z_stream_.get());
if (ret == Z_STREAM_ERROR)
return util::ErrStatus("Error finishing decompression");
}
return util::OkStatus();
}
void GzipTraceParser::NotifyEndOfFile() {}
} // namespace trace_processor
} // namespace perfetto
#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)