| /* |
| * 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 { |
| |
| #if !PERFETTO_IS_AT_LEAST_CPP17() |
| // static |
| constexpr char MetatraceWriter::kDataSourceName[]; |
| #endif |
| |
| 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 |