Skip to content

Commit 125877b

Browse files
authored
tp: speed up JSON tokenization/parsing by ~9x (#1641)
This CL moves away from using jsoncpp as much as possible in trace processor for performance reasons. Turns out jsoncpp really sucks very badly and with a few hundred lines of code, we can destroy it in benchmarks. Before: ``` [898.916] processor_shell.cc:1878 Trace loaded: 453.80 MB in 22.06s (20.6 MB/s) ``` After: ``` [928.441] processor_shell.cc:1878 Trace loaded: 453.80 MB in 2.56s (177.1 MB/s) ``` There should be little-no functional change as a result of this CL. I've added a bunch of tests which pass both before and after to try and ensure there is no behavioural change. It's possible that there are some bugs of course but given the huge perf wins here, I think it's worth landing.
1 parent 51e634e commit 125877b

21 files changed

+2302
-914
lines changed

BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,7 @@ perfetto_filegroup(
22112211
perfetto_filegroup(
22122212
name = "src_trace_processor_importers_json_minimal",
22132213
srcs = [
2214+
"src/trace_processor/importers/json/json_parser.h",
22142215
"src/trace_processor/importers/json/json_utils.cc",
22152216
"src/trace_processor/importers/json/json_utils.h",
22162217
],

CHANGELOG

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ Unreleased:
44
SQL Standard library:
55
*
66
Trace Processor:
7-
*
7+
* Improved performance of parsing JSON by 7x. JSON traces should now load
8+
much faster in the Perfetto UI and the trace processor.
89
UI:
9-
*
10+
* Improved JSON loading performance. See `Trace Processor` section above.
1011
SDK:
1112
*
1213

src/trace_processor/importers/common/BUILD.gn

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ source_set("common") {
107107

108108
source_set("trace_parser_hdr") {
109109
sources = [ "trace_parser.h" ]
110-
deps = [ "../../../../gn:default_deps" ]
110+
deps = [
111+
":parser_types",
112+
"../../../../gn:default_deps",
113+
]
111114
}
112115

113116
source_set("parser_types") {

src/trace_processor/importers/common/parser_types.h

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
#include <array>
2121
#include <cstdint>
2222
#include <functional>
23+
#include <limits>
24+
#include <memory>
2325
#include <optional>
24-
#include <string>
2526
#include <utility>
2627
#include <variant>
28+
#include <vector>
2729

2830
#include "perfetto/trace_processor/ref_counted.h"
2931
#include "perfetto/trace_processor/trace_blob_view.h"
32+
#include "src/trace_processor/containers/interval_tree.h"
3033
#include "src/trace_processor/containers/string_pool.h"
3134
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
3235

@@ -57,16 +60,72 @@ struct alignas(8) InlineSchedWaking {
5760
static_assert(sizeof(InlineSchedWaking) == 16);
5861

5962
struct alignas(8) JsonEvent {
60-
struct Begin {};
61-
struct End {};
62-
struct Scoped {
63-
int64_t dur;
63+
int64_t dur = std::numeric_limits<int64_t>::max();
64+
65+
uint32_t pid = 0;
66+
uint32_t tid = 0;
67+
68+
StringPool::Id name = StringPool::Id::Null();
69+
StringPool::Id cat = StringPool::Id::Null();
70+
71+
union IdStrOrUint64 {
72+
StringPool::Id id_str;
73+
uint64_t id_uint64;
6474
};
65-
struct Other {};
66-
using Type = std::variant<Begin, End, Scoped, Other>;
75+
IdStrOrUint64 id;
76+
IdStrOrUint64 bind_id;
77+
78+
int64_t tts = std::numeric_limits<int64_t>::max();
79+
int64_t tdur = std::numeric_limits<int64_t>::max();
80+
int64_t async_cookie = std::numeric_limits<int64_t>::max();
81+
82+
std::unique_ptr<char[]> args;
83+
84+
char phase = '\0';
85+
86+
uint64_t flow_in : 1;
87+
uint64_t flow_out : 1;
6788

68-
std::string value;
69-
Type type;
89+
uint64_t pid_is_string_id : 1;
90+
uint64_t tid_is_string_id : 1;
91+
92+
uint64_t bind_enclosing_slice : 1;
93+
94+
enum class IdType : uint64_t {
95+
kNone = 0,
96+
kString = 1,
97+
kUint64 = 2,
98+
};
99+
IdType id_type : 2;
100+
IdType bind_id_type : 2;
101+
102+
enum class Scope : uint64_t {
103+
kNone = 0,
104+
kGlobal = 1,
105+
kProcess = 2,
106+
kThread = 3,
107+
};
108+
Scope scope : 2;
109+
110+
enum class AsyncCookieType : uint64_t {
111+
kId,
112+
kId2Local,
113+
kId2Global,
114+
};
115+
AsyncCookieType async_cookie_type : 2;
116+
117+
uint64_t args_size : 43;
118+
119+
JsonEvent()
120+
: flow_in(false),
121+
flow_out(false),
122+
pid_is_string_id(false),
123+
tid_is_string_id(false),
124+
bind_enclosing_slice(false),
125+
id_type(IdType::kNone),
126+
bind_id_type(IdType::kNone),
127+
scope(Scope::kNone),
128+
args_size(0) {}
70129
};
71130
static_assert(sizeof(JsonEvent) % 8 == 0);
72131

src/trace_processor/importers/common/trace_parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <cstdint>
2121
#include <string>
22+
#include "src/trace_processor/importers/common/parser_types.h"
2223

2324
namespace perfetto::trace_processor {
2425
namespace perf_importer {
@@ -63,7 +64,7 @@ class ProtoTraceParser {
6364
class JsonTraceParser {
6465
public:
6566
virtual ~JsonTraceParser();
66-
virtual void ParseJsonPacket(int64_t, std::string) = 0;
67+
virtual void ParseJsonPacket(int64_t, JsonEvent) = 0;
6768
virtual void ParseSystraceLine(int64_t, SystraceLine) = 0;
6869
virtual void ParseLegacyV8ProfileEvent(int64_t, LegacyV8CpuProfileEvent) = 0;
6970
};

src/trace_processor/importers/json/BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ import("../../../../gn/test.gni")
1717

1818
source_set("minimal") {
1919
sources = [
20+
"json_parser.h",
2021
"json_utils.cc",
2122
"json_utils.h",
2223
]
2324
deps = [
2425
"../../../../gn:default_deps",
26+
"../../containers",
2527
"../../storage",
28+
"../../types",
2629
"../common",
2730
]
2831
if (enable_perfetto_trace_processor_json) {
@@ -41,6 +44,7 @@ if (enable_perfetto_trace_processor_json) {
4144
deps = [
4245
":minimal",
4346
"../../../../gn:default_deps",
47+
"../../containers",
4448
"../../sorter",
4549
"../../storage",
4650
"../../tables",

0 commit comments

Comments
 (0)