| /* |
| * Copyright (C) 2018 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/types/trace_processor_context.h" |
| |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| #include <utility> |
| |
| #include "perfetto/base/logging.h" |
| #include "perfetto/trace_processor/basic_types.h" |
| #include "src/trace_processor/forwarding_trace_parser.h" |
| #include "src/trace_processor/importers/common/args_translation_table.h" |
| #include "src/trace_processor/importers/common/clock_converter.h" |
| #include "src/trace_processor/importers/common/clock_tracker.h" |
| #include "src/trace_processor/importers/common/cpu_tracker.h" |
| #include "src/trace_processor/importers/common/event_tracker.h" |
| #include "src/trace_processor/importers/common/flow_tracker.h" |
| #include "src/trace_processor/importers/common/machine_tracker.h" |
| #include "src/trace_processor/importers/common/mapping_tracker.h" |
| #include "src/trace_processor/importers/common/metadata_tracker.h" |
| #include "src/trace_processor/importers/common/process_track_translation_table.h" |
| #include "src/trace_processor/importers/common/process_tracker.h" |
| #include "src/trace_processor/importers/common/registered_file_tracker.h" |
| #include "src/trace_processor/importers/common/sched_event_tracker.h" |
| #include "src/trace_processor/importers/common/slice_tracker.h" |
| #include "src/trace_processor/importers/common/stack_profile_tracker.h" |
| #include "src/trace_processor/importers/common/symbol_tracker.h" |
| #include "src/trace_processor/importers/common/trace_file_tracker.h" |
| #include "src/trace_processor/importers/common/track_compressor.h" |
| #include "src/trace_processor/importers/common/track_tracker.h" |
| #include "src/trace_processor/importers/proto/proto_importer_module.h" |
| #include "src/trace_processor/importers/proto/proto_trace_reader.h" |
| #include "src/trace_processor/storage/trace_storage.h" |
| #include "src/trace_processor/trace_reader_registry.h" |
| #include "src/trace_processor/types/trace_processor_context_ptr.h" |
| |
| namespace perfetto::trace_processor { |
| namespace { |
| |
| template <typename T> |
| using Ptr = TraceProcessorContextPtr<T>; |
| |
| void InitPerTraceAndMachineState(TraceProcessorContext* context) { |
| // Per-machine state (legacy). |
| context->track_tracker = Ptr<TrackTracker>::MakeRoot(context); |
| context->track_compressor = Ptr<TrackCompressor>::MakeRoot(context); |
| context->slice_tracker = Ptr<SliceTracker>::MakeRoot(context); |
| context->slice_translation_table = |
| Ptr<SliceTranslationTable>::MakeRoot(context->storage.get()); |
| context->flow_tracker = Ptr<FlowTracker>::MakeRoot(context); |
| context->process_track_translation_table = |
| Ptr<ProcessTrackTranslationTable>::MakeRoot(context->storage.get()); |
| context->event_tracker = Ptr<EventTracker>::MakeRoot(context); |
| context->sched_event_tracker = Ptr<SchedEventTracker>::MakeRoot(context); |
| context->args_translation_table = |
| Ptr<ArgsTranslationTable>::MakeRoot(context->storage.get()); |
| |
| context->slice_tracker->SetOnSliceBeginCallback( |
| [context](TrackId track_id, SliceId slice_id) { |
| context->flow_tracker->ClosePendingEventsOnTrack(track_id, slice_id); |
| }); |
| } |
| |
| void InitPerMachineState(TraceProcessorContext* context, uint32_t machine_id) { |
| context->symbol_tracker = Ptr<SymbolTracker>::MakeRoot(context); |
| context->machine_tracker = Ptr<MachineTracker>::MakeRoot(context, machine_id); |
| context->process_tracker = Ptr<ProcessTracker>::MakeRoot(context); |
| context->clock_tracker = Ptr<ClockTracker>::MakeRoot(context); |
| context->mapping_tracker = Ptr<MappingTracker>::MakeRoot(context); |
| context->cpu_tracker = Ptr<CpuTracker>::MakeRoot(context); |
| context->stack_profile_tracker = Ptr<StackProfileTracker>::MakeRoot(context); |
| } |
| |
| void CopyPerMachineState(const TraceProcessorContext* source, |
| TraceProcessorContext* dest) { |
| dest->symbol_tracker = source->symbol_tracker.Fork(); |
| dest->machine_tracker = source->machine_tracker.Fork(); |
| dest->process_tracker = source->process_tracker.Fork(); |
| dest->clock_tracker = source->clock_tracker.Fork(); |
| dest->mapping_tracker = source->mapping_tracker.Fork(); |
| dest->cpu_tracker = source->cpu_tracker.Fork(); |
| dest->stack_profile_tracker = source->stack_profile_tracker.Fork(); |
| } |
| |
| void InitPerTraceState(TraceProcessorContext* context, uint32_t raw_trace_id) { |
| context->trace_state = Ptr<TraceProcessorContext::TraceState>::MakeRoot( |
| TraceProcessorContext::TraceState{raw_trace_id}); |
| context->content_analyzer = nullptr; |
| } |
| |
| void CopyTraceState(const TraceProcessorContext* source, |
| TraceProcessorContext* dest) { |
| dest->trace_state = source->trace_state.Fork(); |
| dest->content_analyzer = source->content_analyzer.Fork(); |
| } |
| |
| Ptr<TraceSorter> CreateSorter(TraceProcessorContext* context, |
| const Config& config) { |
| TraceSorter::EventHandling event_handling; |
| switch (config.parsing_mode) { |
| case ParsingMode::kDefault: |
| event_handling = TraceSorter::EventHandling::kSortAndPush; |
| break; |
| case ParsingMode::kTokenizeOnly: |
| event_handling = TraceSorter::EventHandling::kDrop; |
| break; |
| case ParsingMode::kTokenizeAndSort: |
| event_handling = TraceSorter::EventHandling::kSortAndDrop; |
| break; |
| } |
| if (config.enable_dev_features) { |
| auto it = config.dev_flags.find("drop-after-sort"); |
| if (it != config.dev_flags.end() && it->second == "true") { |
| event_handling = TraceSorter::EventHandling::kSortAndDrop; |
| } |
| } |
| return Ptr<TraceSorter>::MakeRoot(context, TraceSorter::SortingMode::kDefault, |
| event_handling); |
| } |
| |
| void InitGlobalState(TraceProcessorContext* context, const Config& config) { |
| // Global state. |
| context->config = config; |
| context->storage = Ptr<TraceStorage>::MakeRoot(config); |
| context->sorter = CreateSorter(context, config); |
| context->reader_registry = Ptr<TraceReaderRegistry>::MakeRoot(); |
| context->global_args_tracker = |
| Ptr<GlobalArgsTracker>::MakeRoot(context->storage.get()); |
| context->trace_file_tracker = Ptr<TraceFileTracker>::MakeRoot(context); |
| context->descriptor_pool_ = Ptr<DescriptorPool>::MakeRoot(); |
| context->forked_context_state = |
| Ptr<TraceProcessorContext::ForkedContextState>::MakeRoot(); |
| context->clock_converter = Ptr<ClockConverter>::MakeRoot(context); |
| context->track_group_idx_state = |
| Ptr<TrackCompressorGroupIdxState>::MakeRoot(); |
| context->register_additional_proto_modules = nullptr; |
| |
| // Per-Trace State (Miscategorized). |
| context->metadata_tracker = |
| Ptr<MetadataTracker>::MakeRoot(context->storage.get()); |
| context->registered_file_tracker = |
| Ptr<RegisteredFileTracker>::MakeRoot(context); |
| context->uuid_state = Ptr<TraceProcessorContext::UuidState>::MakeRoot(); |
| context->heap_graph_tracker = nullptr; |
| } |
| |
| void CopyGlobalState(const TraceProcessorContext* source, |
| TraceProcessorContext* dest) { |
| // Global state. |
| dest->config = source->config; |
| dest->storage = source->storage.Fork(); |
| dest->sorter = source->sorter.Fork(); |
| dest->reader_registry = source->reader_registry.Fork(); |
| dest->global_args_tracker = source->global_args_tracker.Fork(); |
| dest->trace_file_tracker = source->trace_file_tracker.Fork(); |
| dest->descriptor_pool_ = source->descriptor_pool_.Fork(); |
| dest->forked_context_state = source->forked_context_state.Fork(); |
| dest->clock_converter = source->clock_converter.Fork(); |
| dest->track_group_idx_state = source->track_group_idx_state.Fork(); |
| dest->register_additional_proto_modules = |
| source->register_additional_proto_modules; |
| |
| // Per-Trace State (Miscategorized). |
| dest->metadata_tracker = source->metadata_tracker.Fork(); |
| dest->registered_file_tracker = source->registered_file_tracker.Fork(); |
| dest->uuid_state = source->uuid_state.Fork(); |
| dest->heap_graph_tracker = source->heap_graph_tracker.Fork(); |
| } |
| |
| } // namespace |
| |
| TraceProcessorContext::TraceProcessorContext() = default; |
| TraceProcessorContext::TraceProcessorContext(const Config& _config) { |
| InitGlobalState(this, _config); |
| } |
| TraceProcessorContext::~TraceProcessorContext() = default; |
| |
| TraceProcessorContext* TraceProcessorContext::ForkContextForTrace( |
| uint32_t raw_trace_id, |
| uint32_t default_raw_machine_id) const { |
| auto [it, inserted] = |
| forked_context_state->trace_and_machine_to_context.Insert( |
| std::pair(raw_trace_id, default_raw_machine_id), nullptr); |
| if (inserted) { |
| auto context = std::make_unique<TraceProcessorContext>(); |
| CopyGlobalState(this, context.get()); |
| |
| // Initialize per-trace state. |
| auto [trace_it, trace_inserted] = |
| forked_context_state->trace_to_context.Insert(raw_trace_id, |
| context.get()); |
| if (trace_inserted) { |
| InitPerTraceState(context.get(), raw_trace_id); |
| } else { |
| CopyTraceState(*trace_it, context.get()); |
| } |
| |
| // Initialize per-machine state. |
| auto [machine_it, machine_inserted] = |
| forked_context_state->machine_to_context.Insert(default_raw_machine_id, |
| context.get()); |
| if (machine_inserted) { |
| InitPerMachineState(context.get(), default_raw_machine_id); |
| } else { |
| CopyPerMachineState(*machine_it, context.get()); |
| } |
| |
| // Initialize per-trace & per-machine state. |
| InitPerTraceAndMachineState(context.get()); |
| |
| *it = std::move(context); |
| } |
| return it->get(); |
| } |
| |
| TraceProcessorContext* |
| TraceProcessorContext::ForkContextForMachineInCurrentTrace( |
| uint32_t raw_machine_id) const { |
| PERFETTO_CHECK(trace_state); |
| return ForkContextForTrace(trace_state->raw_trace_id, raw_machine_id); |
| } |
| |
| std::optional<MachineId> TraceProcessorContext::machine_id() const { |
| if (!machine_tracker) { |
| // Doesn't require that |machine_tracker| is initialized, e.g. in unit |
| // tests. |
| return std::nullopt; |
| } |
| return machine_tracker->machine_id(); |
| } |
| |
| void TraceProcessorContext::DestroyParsingState() { |
| auto _storage = std::move(storage); |
| |
| // TODO(b/309623584): Decouple from storage and remove from here. This |
| // function should only move storage and delete everything else. |
| auto _heap_graph_tracker = std::move(heap_graph_tracker); |
| auto _clock_converter = std::move(clock_converter); |
| // "to_ftrace" textual converter of the "raw" table requires remembering the |
| // kernel version (inside system_info_tracker) to know how to textualise |
| // sched_switch.prev_state bitflags. |
| auto _system_info_tracker = std::move(system_info_tracker); |
| |
| // "__intrinsic_winscope_proto_to_args_with_defaults" and trace summarization |
| // both require the descriptor pool to be alive. |
| auto _descriptor_pool_ = std::move(descriptor_pool_); |
| |
| this->~TraceProcessorContext(); |
| new (this) TraceProcessorContext(); |
| |
| storage = std::move(_storage); |
| heap_graph_tracker = std::move(_heap_graph_tracker); |
| clock_converter = std::move(_clock_converter); |
| system_info_tracker = std::move(_system_info_tracker); |
| descriptor_pool_ = std::move(_descriptor_pool_); |
| } |
| |
| } // namespace perfetto::trace_processor |