xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/json/json_trace_tokenizer.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 <cstdint>
21 #include <optional>
22 #include <string>
23 #include <vector>
24 
25 #include "perfetto/base/status.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "src/trace_processor/importers/common/chunked_trace_reader.h"
28 #include "src/trace_processor/importers/systrace/systrace_line_tokenizer.h"
29 
30 namespace Json {
31 class Value;
32 }
33 
34 namespace perfetto::trace_processor {
35 
36 class TraceProcessorContext;
37 
38 // Visible for testing.
39 enum class ReadDictRes {
40   kFoundDict,
41   kNeedsMoreData,
42   kEndOfTrace,
43   kEndOfArray,
44 };
45 
46 // Parses at most one JSON dictionary and returns a pointer to the end of it,
47 // or nullptr if no dict could be detected.
48 // This is to avoid decoding the full trace in memory and reduce heap traffic.
49 // E.g.  input:  { a:1 b:{ c:2, d:{ e:3 } } } , { a:4, ... },
50 //       output: [   only this is parsed    ] ^return value points here.
51 // Visible for testing.
52 ReadDictRes ReadOneJsonDict(const char* start,
53                             const char* end,
54                             base::StringView* value,
55                             const char** next);
56 
57 enum class ReadKeyRes {
58   kFoundKey,
59   kNeedsMoreData,
60   kEndOfDictionary,
61   kFatalError,
62 };
63 
64 // Parses at most one JSON key and returns a pointer to the start of the value
65 // associated with that key.
66 // This is to avoid decoding the full trace in memory and reduce heap traffic.
67 // E.g. input:  a:1 b:{ c:2}}
68 //     output:    ^ return value points here, key is set to "a".
69 // Note: even if the whole key may be available, this method will return
70 // kNeedsMoreData until the first character of the value is available.
71 // Visible for testing.
72 ReadKeyRes ReadOneJsonKey(const char* start,
73                           const char* end,
74                           std::string* key,
75                           const char** next);
76 
77 // Takes as input a JSON dictionary and returns the value associated with
78 // the provided key (if it exists).
79 // Implementation note: this method does not currently support dictionaries
80 // which have arrays as JSON values because current users of this method
81 // do not require this.
82 // Visible for testing.
83 base::Status ExtractValueForJsonKey(base::StringView dict,
84                                     const std::string& key,
85                                     std::optional<std::string>* value);
86 
87 enum class ReadSystemLineRes {
88   kFoundLine,
89   kNeedsMoreData,
90   kEndOfSystemTrace,
91   kFatalError,
92 };
93 
94 ReadSystemLineRes ReadOneSystemTraceLine(const char* start,
95                                          const char* end,
96                                          std::string* line,
97                                          const char** next);
98 
99 // Reads a JSON trace in chunks and extracts top level json objects.
100 class JsonTraceTokenizer : public ChunkedTraceReader {
101  public:
102   explicit JsonTraceTokenizer(TraceProcessorContext*);
103   ~JsonTraceTokenizer() override;
104 
105   // ChunkedTraceReader implementation.
106   base::Status Parse(TraceBlobView) override;
107   base::Status NotifyEndOfFile() override;
108 
109  private:
110   // Enum which tracks which type of JSON trace we are dealing with.
111   enum class TraceFormat {
112     // Enum value when ther outer-most layer is a dictionary with multiple
113     // key value pairs
114     kOuterDictionary,
115 
116     // Enum value when we only have trace events (i.e. the outermost
117     // layer is just a array of trace events).
118     kOnlyTraceEvents,
119   };
120 
121   // Enum which tracks our current position within the trace.
122   enum class TracePosition {
123     // This indicates that we are inside the outermost dictionary of the
124     // trace and need to read the next key of the dictionary.
125     // This position is only valid when the |format_| == |kOuterDictionary|.
126     kDictionaryKey,
127 
128     // This indicates we are inside the systemTraceEvents string.
129     // This position is only valid when the |format_| == |kOuterDictionary|.
130     kInsideSystemTraceEventsString,
131 
132     // This indicates where are inside the traceEvents array.
133     kInsideTraceEventsArray,
134 
135     // This indicates we cannot parse any more data in the trace.
136     kEof,
137   };
138 
139   base::Status ParseInternal(const char* start,
140                              const char* end,
141                              const char** out);
142 
143   base::Status ParseV8SampleEvent(base::StringView unparsed);
144 
145   base::Status HandleTraceEvent(const char* start,
146                                 const char* end,
147                                 const char** out);
148 
149   base::Status HandleDictionaryKey(const char* start,
150                                    const char* end,
151                                    const char** out);
152 
153   base::Status HandleSystemTraceEvent(const char* start,
154                                       const char* end,
155                                       const char** out);
156 
157   TraceProcessorContext* const context_;
158 
159   TraceFormat format_ = TraceFormat::kOuterDictionary;
160   TracePosition position_ = TracePosition::kDictionaryKey;
161 
162   SystraceLineTokenizer systrace_line_tokenizer_;
163 
164   uint64_t offset_ = 0;
165   // Used to glue together JSON objects that span across two (or more)
166   // Parse boundaries.
167   std::vector<char> buffer_;
168 };
169 
170 }  // namespace perfetto::trace_processor
171 
172 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
173