blob: 8d121a6b760715315ec82fc5822e40b5b0dfff2e [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.
*/
#include "src/tracing/core/metatrace_writer.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
#include "perfetto/ext/tracing/core/trace_writer.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "protos/perfetto/trace/perfetto/perfetto_metatrace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
namespace perfetto {
MetatraceWriter::MetatraceWriter() : weak_ptr_factory_(this) {}
MetatraceWriter::~MetatraceWriter() {
Disable();
}
void MetatraceWriter::Enable(base::TaskRunner* task_runner,
std::unique_ptr<TraceWriter> trace_writer,
uint32_t tags) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (started_) {
PERFETTO_DFATAL_OR_ELOG("Metatrace already started from this instance");
return;
}
task_runner_ = task_runner;
trace_writer_ = std::move(trace_writer);
auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
bool enabled = metatrace::Enable(
[weak_ptr] {
if (weak_ptr)
weak_ptr->WriteAllAvailableEvents();
},
task_runner, tags);
if (!enabled)
return;
started_ = true;
}
void MetatraceWriter::Disable() {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!started_)
return;
metatrace::Disable();
started_ = false;
trace_writer_.reset();
}
void MetatraceWriter::WriteAllAvailableEvents() {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!started_)
return;
for (auto it = metatrace::RingBuffer::GetReadIterator(); it; ++it) {
auto type_and_id = it->type_and_id.load(std::memory_order_acquire);
if (type_and_id == 0)
break; // Stop at the first incomplete event.
auto packet = trace_writer_->NewTracePacket();
packet->set_timestamp(it->timestamp_ns());
auto* evt = packet->set_perfetto_metatrace();
uint16_t type = type_and_id & metatrace::Record::kTypeMask;
uint16_t id = type_and_id & ~metatrace::Record::kTypeMask;
if (type == metatrace::Record::kTypeCounter) {
evt->set_counter_id(id);
evt->set_counter_value(it->counter_value);
} else {
evt->set_event_id(id);
evt->set_event_duration_ns(it->duration_ns);
}
evt->set_thread_id(static_cast<uint32_t>(it->thread_id));
if (metatrace::RingBuffer::has_overruns())
evt->set_has_overruns(true);
}
// The |it| destructor will automatically update the read index position in
// the meta-trace ring buffer.
}
void MetatraceWriter::WriteAllAndFlushTraceWriter(
std::function<void()> callback) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!started_)
return;
WriteAllAvailableEvents();
trace_writer_->Flush(std::move(callback));
}
} // namespace perfetto