• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
19 
20 #include <stdint.h>
21 
22 #include "src/trace_processor/importers/common/chunked_trace_reader.h"
23 #include "src/trace_processor/importers/systrace/systrace_line_tokenizer.h"
24 #include "src/trace_processor/storage/trace_storage.h"
25 
26 namespace Json {
27 class Value;
28 }
29 
30 namespace perfetto {
31 namespace trace_processor {
32 
33 class TraceProcessorContext;
34 
35 // Visible for testing.
36 enum class ReadDictRes {
37   kFoundDict,
38   kNeedsMoreData,
39   kEndOfTrace,
40   kEndOfArray,
41 };
42 
43 // Parses at most one JSON dictionary and returns a pointer to the end of it,
44 // or nullptr if no dict could be detected.
45 // This is to avoid decoding the full trace in memory and reduce heap traffic.
46 // E.g.  input:  { a:1 b:{ c:2, d:{ e:3 } } } , { a:4, ... },
47 //       output: [   only this is parsed    ] ^return value points here.
48 // Visible for testing.
49 ReadDictRes ReadOneJsonDict(const char* start,
50                             const char* end,
51                             base::StringView* value,
52                             const char** next);
53 
54 enum class ReadKeyRes {
55   kFoundKey,
56   kNeedsMoreData,
57   kEndOfDictionary,
58   kFatalError,
59 };
60 
61 // Parses at most one JSON key and returns a pointer to the start of the value
62 // associated with that key.
63 // This is to avoid decoding the full trace in memory and reduce heap traffic.
64 // E.g. input:  a:1 b:{ c:2}}
65 //     output:    ^ return value points here, key is set to "a".
66 // Note: even if the whole key may be available, this method will return
67 // kNeedsMoreData until the first character of the value is available.
68 // Visible for testing.
69 ReadKeyRes ReadOneJsonKey(const char* start,
70                           const char* end,
71                           std::string* key,
72                           const char** next);
73 
74 // Takes as input a JSON dictionary and returns the value associated with
75 // the provided key (if it exists).
76 // Implementation note: this method does not currently support dictionaries
77 // which have arrays as JSON values because current users of this method
78 // do not require this.
79 // Visible for testing.
80 base::Status ExtractValueForJsonKey(base::StringView dict,
81                                     const std::string& key,
82                                     std::optional<std::string>* value);
83 
84 enum class ReadSystemLineRes {
85   kFoundLine,
86   kNeedsMoreData,
87   kEndOfSystemTrace,
88   kFatalError,
89 };
90 
91 ReadSystemLineRes ReadOneSystemTraceLine(const char* start,
92                                          const char* end,
93                                          std::string* line,
94                                          const char** next);
95 
96 // Reads a JSON trace in chunks and extracts top level json objects.
97 class JsonTraceTokenizer : public ChunkedTraceReader {
98  public:
99   explicit JsonTraceTokenizer(TraceProcessorContext*);
100   ~JsonTraceTokenizer() override;
101 
102   // ChunkedTraceReader implementation.
103   base::Status Parse(TraceBlobView) override;
104   void NotifyEndOfFile() override;
105 
106  private:
107   // Enum which tracks which type of JSON trace we are dealing with.
108   enum class TraceFormat {
109     // Enum value when ther outer-most layer is a dictionary with multiple
110     // key value pairs
111     kOuterDictionary,
112 
113     // Enum value when we only have trace events (i.e. the outermost
114     // layer is just a array of trace events).
115     kOnlyTraceEvents,
116   };
117 
118   // Enum which tracks our current position within the trace.
119   enum class TracePosition {
120     // This indicates that we are inside the outermost dictionary of the
121     // trace and need to read the next key of the dictionary.
122     // This position is only valid when the |format_| == |kOuterDictionary|.
123     kDictionaryKey,
124 
125     // This indicates we are inside the systemTraceEvents string.
126     // This position is only valid when the |format_| == |kOuterDictionary|.
127     kInsideSystemTraceEventsString,
128 
129     // This indicates where are inside the traceEvents array.
130     kInsideTraceEventsArray,
131 
132     // This indicates we cannot parse any more data in the trace.
133     kEof,
134   };
135 
136   base::Status ParseInternal(const char* start,
137                              const char* end,
138                              const char** out);
139 
140   base::Status HandleTraceEvent(const char* start,
141                                 const char* end,
142                                 const char** out);
143 
144   base::Status HandleDictionaryKey(const char* start,
145                                    const char* end,
146                                    const char** out);
147 
148   base::Status HandleSystemTraceEvent(const char* start,
149                                       const char* end,
150                                       const char** out);
151 
152   TraceProcessorContext* const context_;
153 
154   TraceFormat format_ = TraceFormat::kOuterDictionary;
155   TracePosition position_ = TracePosition::kDictionaryKey;
156 
157   SystraceLineTokenizer systrace_line_tokenizer_;
158 
159   uint64_t offset_ = 0;
160   // Used to glue together JSON objects that span across two (or more)
161   // Parse boundaries.
162   std::vector<char> buffer_;
163 };
164 
165 }  // namespace trace_processor
166 }  // namespace perfetto
167 
168 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
169