| /* |
| * 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. |
| */ |
| |
| #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_ |
| #define SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_ |
| |
| #include <stdint.h> |
| |
| #include "src/trace_processor/importers/common/chunked_trace_reader.h" |
| #include "src/trace_processor/importers/systrace/systrace_line_tokenizer.h" |
| #include "src/trace_processor/storage/trace_storage.h" |
| |
| namespace Json { |
| class Value; |
| } |
| |
| namespace perfetto { |
| namespace trace_processor { |
| |
| class TraceProcessorContext; |
| |
| // Visible for testing. |
| enum class ReadDictRes { |
| kFoundDict, |
| kNeedsMoreData, |
| kEndOfTrace, |
| kEndOfArray, |
| }; |
| |
| // Parses at most one JSON dictionary and returns a pointer to the end of it, |
| // or nullptr if no dict could be detected. |
| // This is to avoid decoding the full trace in memory and reduce heap traffic. |
| // E.g. input: { a:1 b:{ c:2, d:{ e:3 } } } , { a:4, ... }, |
| // output: [ only this is parsed ] ^return value points here. |
| // Visible for testing. |
| ReadDictRes ReadOneJsonDict(const char* start, |
| const char* end, |
| base::StringView* value, |
| const char** next); |
| |
| enum class ReadKeyRes { |
| kFoundKey, |
| kNeedsMoreData, |
| kEndOfDictionary, |
| kFatalError, |
| }; |
| |
| // Parses at most one JSON key and returns a pointer to the start of the value |
| // associated with that key. |
| // This is to avoid decoding the full trace in memory and reduce heap traffic. |
| // E.g. input: a:1 b:{ c:2}} |
| // output: ^ return value points here, key is set to "a". |
| // Note: even if the whole key may be available, this method will return |
| // kNeedsMoreData until the first character of the value is available. |
| // Visible for testing. |
| ReadKeyRes ReadOneJsonKey(const char* start, |
| const char* end, |
| std::string* key, |
| const char** next); |
| |
| // Takes as input a JSON dictionary and returns the value associated with |
| // the provided key (if it exists). |
| // Implementation note: this method does not currently support dictionaries |
| // which have arrays as JSON values because current users of this method |
| // do not require this. |
| // Visible for testing. |
| base::Status ExtractValueForJsonKey(base::StringView dict, |
| const std::string& key, |
| std::optional<std::string>* value); |
| |
| enum class ReadSystemLineRes { |
| kFoundLine, |
| kNeedsMoreData, |
| kEndOfSystemTrace, |
| kFatalError, |
| }; |
| |
| ReadSystemLineRes ReadOneSystemTraceLine(const char* start, |
| const char* end, |
| std::string* line, |
| const char** next); |
| |
| // Reads a JSON trace in chunks and extracts top level json objects. |
| class JsonTraceTokenizer : public ChunkedTraceReader { |
| public: |
| explicit JsonTraceTokenizer(TraceProcessorContext*); |
| ~JsonTraceTokenizer() override; |
| |
| // ChunkedTraceReader implementation. |
| base::Status Parse(TraceBlobView) override; |
| void NotifyEndOfFile() override; |
| |
| private: |
| // Enum which tracks which type of JSON trace we are dealing with. |
| enum class TraceFormat { |
| // Enum value when ther outer-most layer is a dictionary with multiple |
| // key value pairs |
| kOuterDictionary, |
| |
| // Enum value when we only have trace events (i.e. the outermost |
| // layer is just a array of trace events). |
| kOnlyTraceEvents, |
| }; |
| |
| // Enum which tracks our current position within the trace. |
| enum class TracePosition { |
| // This indicates that we are inside the outermost dictionary of the |
| // trace and need to read the next key of the dictionary. |
| // This position is only valid when the |format_| == |kOuterDictionary|. |
| kDictionaryKey, |
| |
| // This indicates we are inside the systemTraceEvents string. |
| // This position is only valid when the |format_| == |kOuterDictionary|. |
| kInsideSystemTraceEventsString, |
| |
| // This indicates where are inside the traceEvents array. |
| kInsideTraceEventsArray, |
| |
| // This indicates we cannot parse any more data in the trace. |
| kEof, |
| }; |
| |
| base::Status ParseInternal(const char* start, |
| const char* end, |
| const char** out); |
| |
| base::Status HandleTraceEvent(const char* start, |
| const char* end, |
| const char** out); |
| |
| base::Status HandleDictionaryKey(const char* start, |
| const char* end, |
| const char** out); |
| |
| base::Status HandleSystemTraceEvent(const char* start, |
| const char* end, |
| const char** out); |
| |
| TraceProcessorContext* const context_; |
| |
| TraceFormat format_ = TraceFormat::kOuterDictionary; |
| TracePosition position_ = TracePosition::kDictionaryKey; |
| |
| SystraceLineTokenizer systrace_line_tokenizer_; |
| |
| uint64_t offset_ = 0; |
| // Used to glue together JSON objects that span across two (or more) |
| // Parse boundaries. |
| std::vector<char> buffer_; |
| }; |
| |
| } // namespace trace_processor |
| } // namespace perfetto |
| |
| #endif // SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_ |