/* * Copyright (C) 2024 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/importers/instruments/instruments_xml_tokenizer.h" #include <map> #include <expat.h> #include <stdint.h> #include "perfetto/base/status.h" #include "perfetto/ext/base/status_or.h" #include "perfetto/public/fnv1a.h" #include "protos/perfetto/trace/clock_snapshot.pbzero.h" #include "src/trace_processor/importers/common/clock_tracker.h" #include "src/trace_processor/importers/common/stack_profile_tracker.h" #include "src/trace_processor/importers/instruments/row.h" #include "src/trace_processor/importers/instruments/row_data_tracker.h" #include "src/trace_processor/sorter/trace_sorter.h" namespace perfetto::trace_processor::instruments_importer { namespace { std::string MakeTrimmed(const char* chars, int len) { … } } // namespace // The Instruments XML tokenizer reads instruments traces exported with: // // xctrace export --input /path/to/profile.trace --xpath // '//trace-toc/run/data/table[@schema="os-signpost and // @category="PointsOfInterest"] | // //trace-toc/run/data/table[@schema="time-sample"]' // // This exports two tables: // 1. Points of interest signposts // 2. Time samples // // The first is used for clock synchronization -- perfetto emits signpost events // during tracing which allow synchronization of the xctrace clock (relative to // start of profiling) with the perfetto boottime clock. The second contains // the samples themselves. // // The expected format of the rows in the clock sync table is: // // <row> // <event-time>1234</event-time> // <subsystem>dev.perfetto.clock_sync</subsystem> // <os-log-metadata> // <uint64>5678</uint64> // </os-log-metadata> // </row> // // There may be other rows with other data (from other subsystems), and // additional data in the row (such as thread data and other metadata) -- this // can be safely ignored. // // The expected format of the rows in the time sample table is: // // <row> // <sample-time>1234</sample-time> // <thread fmt="Thread name"> // <tid>1</tid> // <process fmt="Process name"> // <pid>1<pid> // </process> // </thread> // <core>0</core> // <backtrace> // <frame addr="0x120001234"> // <binary // name="MyBinary" UUID="01234567-89ABC-CDEF-0123-456789ABCDEF" // load-addr="0x120000000" path="/path/to/MyBinary.app/MyBinary" /> // </frame> // ... more frames ... // </row> // // Here we do not expect other rows with other data -- every row should have a // backtrace, and we use the presence of a backtrace to distinguish time samples // and clock sync eventst. However, there can be additional data in the row // (such as other metadata) -- this can be safely ignored. // // In addition, the XML format annotates elements with ids, to later reuse the // same data by id without needing to repeat its contents. For example, you // might have thread data for a sample: // // <thread id="11" fmt="My Thread"><tid id="12">10</tid>...</thread> // // and subsequent samples on that thread will simply have // // <thread ref="11" /> // // This means that most elements have to have their pertinent data cached by id, // including any data store in child elements (which themselves also have to // be cached by id, like the <tid> in the example above). // // This importer reads the XML data using a streaming XML parser, which means // it has to maintain some parsing state (such as the current stack of tags, or // the current element for which we are reading data). class InstrumentsXmlTokenizer::Impl { … }; InstrumentsXmlTokenizer::InstrumentsXmlTokenizer(TraceProcessorContext* context) : … { … } InstrumentsXmlTokenizer::~InstrumentsXmlTokenizer() { … } base::Status InstrumentsXmlTokenizer::Parse(TraceBlobView view) { … } [[nodiscard]] base::Status InstrumentsXmlTokenizer::NotifyEndOfFile() { … } } // namespace perfetto::trace_processor::instruments_importer