blob: 61f1d77819e52a44ef7b75dee5dbaff83f2a351d [file] [log] [blame]
/*
* 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_