/* * 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/trace_processor/fuchsia_trace_parser.h" #include "src/trace_processor/process_tracker.h" #include "src/trace_processor/slice_tracker.h" namespace perfetto { namespace trace_processor { namespace { // Record Types constexpr uint32_t kEvent = 4; // Event Types constexpr uint32_t kDurationBegin = 2; constexpr uint32_t kDurationEnd = 3; constexpr uint32_t kDurationComplete = 4; } // namespace FuchsiaTraceParser::FuchsiaTraceParser(TraceProcessorContext* context) : context_(context) {} FuchsiaTraceParser::~FuchsiaTraceParser() = default; void FuchsiaTraceParser::ParseFtracePacket(uint32_t, int64_t, TraceSorter::TimestampedTracePiece) { PERFETTO_FATAL("Fuchsia Trace Parser cannot handle ftrace packets."); } void FuchsiaTraceParser::ParseTracePacket( int64_t, TraceSorter::TimestampedTracePiece ttp) { PERFETTO_DCHECK(ttp.fuchsia_provider_view != nullptr); // The timestamp is also present in the record, so we'll ignore the one passed // as an argument. const uint64_t* current = reinterpret_cast(ttp.blob_view.data()); FuchsiaProviderView* provider_view = ttp.fuchsia_provider_view.get(); ProcessTracker* procs = context_->process_tracker.get(); SliceTracker* slices = context_->slice_tracker.get(); uint64_t header = *current++; uint32_t record_type = fuchsia_trace_utils::ReadField(header, 0, 3); switch (record_type) { case kEvent: { uint32_t event_type = fuchsia_trace_utils::ReadField(header, 16, 19); uint32_t n_args = fuchsia_trace_utils::ReadField(header, 20, 23); uint32_t thread_ref = fuchsia_trace_utils::ReadField(header, 24, 31); uint32_t cat_ref = fuchsia_trace_utils::ReadField(header, 32, 47); uint32_t name_ref = fuchsia_trace_utils::ReadField(header, 48, 63); int64_t ts = fuchsia_trace_utils::ReadTimestamp( ¤t, provider_view->get_ticks_per_second()); fuchsia_trace_utils::ThreadInfo tinfo; if (fuchsia_trace_utils::IsInlineThread(thread_ref)) { tinfo = fuchsia_trace_utils::ReadInlineThread(¤t); } else { tinfo = provider_view->GetThread(thread_ref); } StringId cat; if (fuchsia_trace_utils::IsInlineString(cat_ref)) { cat = context_->storage->InternString( fuchsia_trace_utils::ReadInlineString(¤t, cat_ref)); } else { cat = provider_view->GetString(cat_ref); } StringId name; if (fuchsia_trace_utils::IsInlineString(name_ref)) { name = context_->storage->InternString( fuchsia_trace_utils::ReadInlineString(¤t, name_ref)); } else { name = provider_view->GetString(name_ref); } // Skip over all the args, so that the |ReadTimestamp| call for complete // durations has the pointer in the right place. for (uint32_t i = 0; i < n_args; i++) { uint64_t arg_header = *current; uint32_t arg_size_words = fuchsia_trace_utils::ReadField(arg_header, 4, 15); current += arg_size_words; } switch (event_type) { case kDurationBegin: { UniqueTid utid = procs->UpdateThread(static_cast(tinfo.tid), static_cast(tinfo.pid)); slices->Begin(ts, utid, cat, name); break; } case kDurationEnd: { UniqueTid utid = procs->UpdateThread(static_cast(tinfo.tid), static_cast(tinfo.pid)); slices->End(ts, utid, cat, name); break; } case kDurationComplete: { int64_t end_ts = fuchsia_trace_utils::ReadTimestamp( ¤t, provider_view->get_ticks_per_second()); UniqueTid utid = procs->UpdateThread(static_cast(tinfo.tid), static_cast(tinfo.pid)); slices->Scoped(ts, utid, cat, name, end_ts - ts); break; } } break; } default: { PERFETTO_DFATAL("Unknown record type %d in FuchsiaTraceParser", record_type); break; } } } } // namespace trace_processor } // namespace perfetto