xref: /aosp_15_r20/external/perfetto/src/trace_processor/export_json_unittest.cc (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 #include "perfetto/ext/trace_processor/export_json.h"
18 
19 #include <json/config.h>
20 #include <json/reader.h>
21 #include <json/value.h>
22 #include <array>
23 #include <cstdint>
24 #include <cstdio>
25 #include <cstring>
26 #include <limits>
27 #include <memory>
28 #include <optional>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include "perfetto/base/status.h"
34 #include "perfetto/ext/base/string_utils.h"
35 #include "perfetto/ext/base/string_view.h"
36 #include "perfetto/ext/base/temp_file.h"
37 #include "src/trace_processor/export_json.h"
38 #include "src/trace_processor/importers/common/args_tracker.h"
39 #include "src/trace_processor/importers/common/cpu_tracker.h"
40 #include "src/trace_processor/importers/common/event_tracker.h"
41 #include "src/trace_processor/importers/common/machine_tracker.h"
42 #include "src/trace_processor/importers/common/metadata_tracker.h"
43 #include "src/trace_processor/importers/common/process_track_translation_table.h"
44 #include "src/trace_processor/importers/common/process_tracker.h"
45 #include "src/trace_processor/importers/common/track_tracker.h"
46 #include "src/trace_processor/importers/common/tracks.h"
47 #include "src/trace_processor/importers/common/tracks_common.h"
48 #include "src/trace_processor/importers/common/tracks_internal.h"
49 #include "src/trace_processor/importers/proto/track_event_tracker.h"
50 #include "src/trace_processor/storage/metadata.h"
51 #include "src/trace_processor/storage/stats.h"
52 #include "src/trace_processor/storage/trace_storage.h"
53 #include "src/trace_processor/tables/metadata_tables_py.h"
54 #include "src/trace_processor/types/trace_processor_context.h"
55 #include "src/trace_processor/types/variadic.h"
56 #include "test/gtest_and_gmock.h"
57 
58 namespace perfetto::trace_processor::json {
59 namespace {
60 
ReadFile(FILE * input)61 std::string ReadFile(FILE* input) {
62   fseek(input, 0, SEEK_SET);
63   const int kBufSize = 10000;
64   char buffer[kBufSize];
65   size_t ret = fread(buffer, sizeof(char), kBufSize, input);
66   EXPECT_GT(ret, 0u);
67   return {buffer, ret};
68 }
69 
70 class StringOutputWriter : public OutputWriter {
71  public:
StringOutputWriter()72   StringOutputWriter() { str_.reserve(1024); }
~StringOutputWriter()73   ~StringOutputWriter() override {}
74 
AppendString(const std::string & str)75   base::Status AppendString(const std::string& str) override {
76     str_ += str;
77     return base::OkStatus();
78   }
79 
TakeStr()80   std::string TakeStr() { return std::move(str_); }
81 
82  private:
83   std::string str_;
84 };
85 
86 class ExportJsonTest : public ::testing::Test {
87  public:
ExportJsonTest()88   ExportJsonTest() {
89     context_.storage.reset(new TraceStorage());
90     context_.global_args_tracker.reset(
91         new GlobalArgsTracker(context_.storage.get()));
92     context_.args_tracker.reset(new ArgsTracker(&context_));
93     context_.event_tracker.reset(new EventTracker(&context_));
94     context_.track_tracker.reset(new TrackTracker(&context_));
95     context_.machine_tracker.reset(new MachineTracker(&context_, 0));
96     context_.cpu_tracker.reset(new CpuTracker(&context_));
97     context_.metadata_tracker.reset(
98         new MetadataTracker(context_.storage.get()));
99     context_.process_tracker.reset(new ProcessTracker(&context_));
100     context_.process_track_translation_table.reset(
101         new ProcessTrackTranslationTable(context_.storage.get()));
102   }
103 
ToJson(ArgumentFilterPredicate argument_filter=nullptr,MetadataFilterPredicate metadata_filter=nullptr,LabelFilterPredicate label_filter=nullptr) const104   std::string ToJson(ArgumentFilterPredicate argument_filter = nullptr,
105                      MetadataFilterPredicate metadata_filter = nullptr,
106                      LabelFilterPredicate label_filter = nullptr) const {
107     StringOutputWriter writer;
108     base::Status status =
109         ExportJson(context_.storage.get(), &writer, std::move(argument_filter),
110                    std::move(metadata_filter), std::move(label_filter));
111     EXPECT_TRUE(status.ok());
112     return writer.TakeStr();
113   }
114 
ToJsonValue(const std::string & json)115   static Json::Value ToJsonValue(const std::string& json) {
116     Json::CharReaderBuilder b;
117     auto reader = std::unique_ptr<Json::CharReader>(b.newCharReader());
118     Json::Value result;
119     EXPECT_TRUE(reader->parse(json.data(), json.data() + json.length(), &result,
120                               nullptr))
121         << json;
122     return result;
123   }
124 
125  protected:
126   TraceProcessorContext context_;
127 };
128 
TEST_F(ExportJsonTest,EmptyStorage)129 TEST_F(ExportJsonTest, EmptyStorage) {
130   base::TempFile temp_file = base::TempFile::Create();
131   FILE* output = fopen(temp_file.path().c_str(), "w+e");
132   base::Status status = ExportJson(context_.storage.get(), output);
133 
134   EXPECT_TRUE(status.ok());
135 
136   Json::Value result = ToJsonValue(ReadFile(output));
137   EXPECT_EQ(result["traceEvents"].size(), 0u);
138 }
139 
TEST_F(ExportJsonTest,StorageWithOneSlice)140 TEST_F(ExportJsonTest, StorageWithOneSlice) {
141   const int64_t kTimestamp = 10000000;
142   const int64_t kDuration = 10000;
143   const int64_t kThreadTimestamp = 20000000;
144   const int64_t kThreadDuration = 20000;
145   const int64_t kThreadInstructionCount = 30000000;
146   const int64_t kThreadInstructionDelta = 30000;
147   const uint32_t kThreadID = 100;
148   const char* kCategory = "cat";
149   const char* kName = "name";
150 
151   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
152   TrackId track = context_.track_tracker->InternThreadTrack(utid);
153   context_.args_tracker->Flush();  // Flush track args.
154   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
155   StringId name_id = context_.storage->InternString(base::StringView(kName));
156   // The thread_slice table is a sub table of slice.
157   context_.storage->mutable_slice_table()->Insert(
158       {kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0, SliceId(0u), 0,
159        kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
160        kThreadInstructionDelta});
161 
162   base::TempFile temp_file = base::TempFile::Create();
163   FILE* output = fopen(temp_file.path().c_str(), "w+e");
164   base::Status status = ExportJson(context_.storage.get(), output);
165 
166   EXPECT_TRUE(status.ok());
167 
168   Json::Value result = ToJsonValue(ReadFile(output));
169   EXPECT_EQ(result["traceEvents"].size(), 1u);
170 
171   Json::Value event = result["traceEvents"][0];
172   EXPECT_EQ(event["ph"].asString(), "X");
173   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
174   EXPECT_EQ(event["dur"].asInt64(), kDuration / 1000);
175   EXPECT_EQ(event["tts"].asInt64(), kThreadTimestamp / 1000);
176   EXPECT_EQ(event["tdur"].asInt64(), kThreadDuration / 1000);
177   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
178   EXPECT_EQ(event["tidelta"].asInt64(), kThreadInstructionDelta);
179   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
180   EXPECT_EQ(event["cat"].asString(), kCategory);
181   EXPECT_EQ(event["name"].asString(), kName);
182   EXPECT_TRUE(event["args"].isObject());
183   EXPECT_EQ(event["args"].size(), 0u);
184 }
185 
TEST_F(ExportJsonTest,StorageWithOneUnfinishedSlice)186 TEST_F(ExportJsonTest, StorageWithOneUnfinishedSlice) {
187   const int64_t kTimestamp = 10000000;
188   const int64_t kDuration = -1;
189   const int64_t kThreadTimestamp = 20000000;
190   const int64_t kThreadDuration = -1;
191   const int64_t kThreadInstructionCount = 30000000;
192   const int64_t kThreadInstructionDelta = -1;
193   const uint32_t kThreadID = 100;
194   const char* kCategory = "cat";
195   const char* kName = "name";
196 
197   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
198   TrackId track = context_.track_tracker->InternThreadTrack(utid);
199   context_.args_tracker->Flush();  // Flush track args.
200   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
201   StringId name_id = context_.storage->InternString(base::StringView(kName));
202   context_.storage->mutable_slice_table()->Insert(
203       {kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0, SliceId(0u), 0,
204        kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
205        kThreadInstructionDelta});
206 
207   base::TempFile temp_file = base::TempFile::Create();
208   FILE* output = fopen(temp_file.path().c_str(), "w+e");
209   base::Status status = ExportJson(context_.storage.get(), output);
210 
211   EXPECT_TRUE(status.ok());
212 
213   Json::Value result = ToJsonValue(ReadFile(output));
214   EXPECT_EQ(result["traceEvents"].size(), 1u);
215 
216   Json::Value event = result["traceEvents"][0];
217   EXPECT_EQ(event["ph"].asString(), "B");
218   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
219   EXPECT_FALSE(event.isMember("dur"));
220   EXPECT_EQ(event["tts"].asInt64(), kThreadTimestamp / 1000);
221   EXPECT_FALSE(event.isMember("tdur"));
222   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
223   EXPECT_FALSE(event.isMember("tidelta"));
224   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
225   EXPECT_EQ(event["cat"].asString(), kCategory);
226   EXPECT_EQ(event["name"].asString(), kName);
227   EXPECT_TRUE(event["args"].isObject());
228   EXPECT_EQ(event["args"].size(), 0u);
229 }
230 
TEST_F(ExportJsonTest,StorageWithThreadName)231 TEST_F(ExportJsonTest, StorageWithThreadName) {
232   const uint32_t kThreadID = 100;
233   const char* kName = "thread";
234 
235   tables::ThreadTable::Row row(kThreadID);
236   row.name = context_.storage->InternString(base::StringView(kName));
237   context_.storage->mutable_thread_table()->Insert(row);
238 
239   base::TempFile temp_file = base::TempFile::Create();
240   FILE* output = fopen(temp_file.path().c_str(), "w+e");
241   base::Status status = ExportJson(context_.storage.get(), output);
242 
243   EXPECT_TRUE(status.ok());
244 
245   Json::Value result = ToJsonValue(ReadFile(output));
246   EXPECT_EQ(result["traceEvents"].size(), 1u);
247 
248   Json::Value event = result["traceEvents"][0];
249   EXPECT_EQ(event["ph"].asString(), "M");
250   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
251   EXPECT_EQ(event["name"].asString(), "thread_name");
252   EXPECT_EQ(event["args"]["name"].asString(), kName);
253 }
254 
TEST_F(ExportJsonTest,SystemEventsIgnored)255 TEST_F(ExportJsonTest, SystemEventsIgnored) {
256   TrackId track =
257       context_.track_tracker->InternProcessTrack(tracks::unknown, 0);
258   context_.args_tracker->Flush();  // Flush track args.
259 
260   // System events have no category.
261   StringId cat_id = kNullStringId;
262   StringId name_id = context_.storage->InternString("name");
263   context_.storage->mutable_slice_table()->Insert(
264       {0, 0, track, cat_id, name_id, 0, 0, 0});
265 
266   base::TempFile temp_file = base::TempFile::Create();
267   FILE* output = fopen(temp_file.path().c_str(), "w+e");
268   base::Status status = ExportJson(context_.storage.get(), output);
269 
270   EXPECT_TRUE(status.ok());
271 
272   Json::Value result = ToJsonValue(ReadFile(output));
273   EXPECT_EQ(result["traceEvents"].size(), 0u);
274 }
275 
TEST_F(ExportJsonTest,StorageWithMetadata)276 TEST_F(ExportJsonTest, StorageWithMetadata) {
277   const char* kDescription = "description";
278   const char* kBenchmarkName = "benchmark name";
279   const char* kStoryName = "story name";
280   const char* kStoryTag1 = "tag1";
281   const char* kStoryTag2 = "tag2";
282   const char* kDynamicKey = "dyn_key1";
283   const int64_t kBenchmarkStart = 1000000;
284   const int64_t kStoryStart = 2000000;
285   const bool kHadFailures = true;
286 
287   StringId desc_id =
288       context_.storage->InternString(base::StringView(kDescription));
289   Variadic description = Variadic::String(desc_id);
290   context_.metadata_tracker->SetMetadata(metadata::benchmark_description,
291                                          description);
292 
293   StringId benchmark_name_id =
294       context_.storage->InternString(base::StringView(kBenchmarkName));
295   Variadic benchmark_name = Variadic::String(benchmark_name_id);
296   context_.metadata_tracker->SetMetadata(metadata::benchmark_name,
297                                          benchmark_name);
298 
299   StringId story_name_id =
300       context_.storage->InternString(base::StringView(kStoryName));
301   Variadic story_name = Variadic::String(story_name_id);
302   context_.metadata_tracker->SetMetadata(metadata::benchmark_story_name,
303                                          story_name);
304 
305   StringId tag1_id =
306       context_.storage->InternString(base::StringView(kStoryTag1));
307   StringId tag2_id =
308       context_.storage->InternString(base::StringView(kStoryTag2));
309   Variadic tag1 = Variadic::String(tag1_id);
310   Variadic tag2 = Variadic::String(tag2_id);
311   context_.metadata_tracker->AppendMetadata(metadata::benchmark_story_tags,
312                                             tag1);
313   context_.metadata_tracker->AppendMetadata(metadata::benchmark_story_tags,
314                                             tag2);
315 
316   Variadic benchmark_start = Variadic::Integer(kBenchmarkStart);
317   context_.metadata_tracker->SetMetadata(metadata::benchmark_start_time_us,
318                                          benchmark_start);
319 
320   Variadic story_start = Variadic::Integer(kStoryStart);
321   context_.metadata_tracker->SetMetadata(metadata::benchmark_story_run_time_us,
322                                          story_start);
323 
324   Variadic had_failures = Variadic::Integer(kHadFailures);
325   context_.metadata_tracker->SetMetadata(metadata::benchmark_had_failures,
326                                          had_failures);
327 
328   // Metadata entries with dynamic keys are not currently exported from the
329   // metadata table (the Chrome metadata is exported directly from the raw
330   // table).
331   StringId dynamic_key_id =
332       context_.storage->InternString(base::StringView(kDynamicKey));
333   context_.metadata_tracker->SetDynamicMetadata(dynamic_key_id, had_failures);
334 
335   base::TempFile temp_file = base::TempFile::Create();
336   FILE* output = fopen(temp_file.path().c_str(), "w+e");
337   base::Status status = ExportJson(context_.storage.get(), output);
338 
339   EXPECT_TRUE(status.ok());
340 
341   Json::Value result = ToJsonValue(ReadFile(output));
342 
343   EXPECT_TRUE(result.isMember("metadata"));
344   EXPECT_TRUE(result["metadata"].isMember("telemetry"));
345   Json::Value telemetry_metadata = result["metadata"]["telemetry"];
346 
347   EXPECT_EQ(telemetry_metadata["benchmarkDescriptions"].size(), 1u);
348   EXPECT_EQ(telemetry_metadata["benchmarkDescriptions"][0].asString(),
349             kDescription);
350 
351   EXPECT_EQ(telemetry_metadata["benchmarks"].size(), 1u);
352   EXPECT_EQ(telemetry_metadata["benchmarks"][0].asString(), kBenchmarkName);
353 
354   EXPECT_EQ(telemetry_metadata["stories"].size(), 1u);
355   EXPECT_EQ(telemetry_metadata["stories"][0].asString(), kStoryName);
356 
357   EXPECT_EQ(telemetry_metadata["storyTags"].size(), 2u);
358   EXPECT_EQ(telemetry_metadata["storyTags"][0].asString(), kStoryTag1);
359   EXPECT_EQ(telemetry_metadata["storyTags"][1].asString(), kStoryTag2);
360 
361   EXPECT_DOUBLE_EQ(telemetry_metadata["benchmarkStart"].asInt(),
362                    kBenchmarkStart / 1000.0);
363 
364   EXPECT_DOUBLE_EQ(telemetry_metadata["traceStart"].asInt(),
365                    kStoryStart / 1000.0);
366 
367   EXPECT_EQ(telemetry_metadata["hadFailures"].size(), 1u);
368   EXPECT_EQ(telemetry_metadata["hadFailures"][0].asBool(), kHadFailures);
369 
370   EXPECT_FALSE(result["metadata"].isMember(kDynamicKey));
371 }
372 
TEST_F(ExportJsonTest,StorageWithStats)373 TEST_F(ExportJsonTest, StorageWithStats) {
374   int64_t kProducers = 10;
375   int64_t kBufferSize0 = 1000;
376   int64_t kBufferSize1 = 2000;
377   int64_t kFtraceBegin = 3000;
378 
379   context_.storage->SetStats(stats::traced_producers_connected, kProducers);
380   context_.storage->SetIndexedStats(stats::traced_buf_buffer_size, 0,
381                                     kBufferSize0);
382   context_.storage->SetIndexedStats(stats::traced_buf_buffer_size, 1,
383                                     kBufferSize1);
384   context_.storage->SetIndexedStats(stats::ftrace_cpu_bytes_begin, 0,
385                                     kFtraceBegin);
386 
387   base::TempFile temp_file = base::TempFile::Create();
388   FILE* output = fopen(temp_file.path().c_str(), "w+e");
389   base::Status status = ExportJson(context_.storage.get(), output);
390   EXPECT_TRUE(status.ok());
391 
392   Json::Value result = ToJsonValue(ReadFile(output));
393 
394   EXPECT_TRUE(result.isMember("metadata"));
395   EXPECT_TRUE(result["metadata"].isMember("trace_processor_stats"));
396   Json::Value stats = result["metadata"]["trace_processor_stats"];
397 
398   EXPECT_EQ(stats["traced_producers_connected"].asInt(), kProducers);
399   EXPECT_EQ(stats["traced_buf"].size(), 2u);
400   EXPECT_EQ(stats["traced_buf"][0]["buffer_size"].asInt(), kBufferSize0);
401   EXPECT_EQ(stats["traced_buf"][1]["buffer_size"].asInt(), kBufferSize1);
402   EXPECT_EQ(stats["ftrace_cpu_bytes_begin"].size(), 1u);
403   EXPECT_EQ(stats["ftrace_cpu_bytes_begin"][0].asInt(), kFtraceBegin);
404 }
405 
TEST_F(ExportJsonTest,StorageWithChromeMetadata)406 TEST_F(ExportJsonTest, StorageWithChromeMetadata) {
407   const char* kName1 = "name1";
408   const char* kName2 = "name2";
409   const char* kValue1 = "value1";
410   const int kValue2 = 222;
411 
412   TraceStorage* storage = context_.storage.get();
413 
414   auto ucpu = context_.cpu_tracker->GetOrCreateCpu(0);
415   RawId id = storage->mutable_raw_table()
416                  ->Insert({0, storage->InternString("chrome_event.metadata"), 0,
417                            0, 0, ucpu})
418                  .id;
419 
420   StringId name1_id = storage->InternString(base::StringView(kName1));
421   StringId name2_id = storage->InternString(base::StringView(kName2));
422   StringId value1_id = storage->InternString(base::StringView(kValue1));
423 
424   context_.args_tracker->AddArgsTo(id)
425       .AddArg(name1_id, Variadic::String(value1_id))
426       .AddArg(name2_id, Variadic::Integer(kValue2));
427   context_.args_tracker->Flush();
428 
429   base::TempFile temp_file = base::TempFile::Create();
430   FILE* output = fopen(temp_file.path().c_str(), "w+e");
431   base::Status status = ExportJson(storage, output);
432   EXPECT_TRUE(status.ok());
433 
434   Json::Value result = ToJsonValue(ReadFile(output));
435 
436   EXPECT_TRUE(result.isMember("metadata"));
437   Json::Value metadata = result["metadata"];
438 
439   EXPECT_EQ(metadata[kName1].asString(), kValue1);
440   EXPECT_EQ(metadata[kName2].asInt(), kValue2);
441 }
442 
TEST_F(ExportJsonTest,StorageWithArgs)443 TEST_F(ExportJsonTest, StorageWithArgs) {
444   const char* kCategory = "cat";
445   const char* kName = "name";
446   const char* kSrc = "source_file.cc";
447 
448   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
449   TrackId track = context_.track_tracker->InternThreadTrack(utid);
450   context_.args_tracker->Flush();  // Flush track args.
451   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
452   StringId name_id = context_.storage->InternString(base::StringView(kName));
453   context_.storage->mutable_slice_table()->Insert(
454       {0, 0, track, cat_id, name_id, 0, 0, 0});
455 
456   StringId arg_key_id = context_.storage->InternString(
457       base::StringView("task.posted_from.file_name"));
458   StringId arg_value_id =
459       context_.storage->InternString(base::StringView(kSrc));
460   GlobalArgsTracker::Arg arg;
461   arg.flat_key = arg_key_id;
462   arg.key = arg_key_id;
463   arg.value = Variadic::String(arg_value_id);
464   ArgSetId args = context_.global_args_tracker->AddArgSet({arg}, 0, 1);
465   auto& slice = *context_.storage->mutable_slice_table();
466   slice[0].set_arg_set_id(args);
467 
468   base::TempFile temp_file = base::TempFile::Create();
469   FILE* output = fopen(temp_file.path().c_str(), "w+e");
470   base::Status status = ExportJson(context_.storage.get(), output);
471 
472   EXPECT_TRUE(status.ok());
473 
474   Json::Value result = ToJsonValue(ReadFile(output));
475   EXPECT_EQ(result["traceEvents"].size(), 1u);
476 
477   Json::Value event = result["traceEvents"][0];
478   EXPECT_EQ(event["cat"].asString(), kCategory);
479   EXPECT_EQ(event["name"].asString(), kName);
480   EXPECT_EQ(event["args"]["src"].asString(), kSrc);
481 }
482 
TEST_F(ExportJsonTest,StorageWithSliceAndFlowEventArgs)483 TEST_F(ExportJsonTest, StorageWithSliceAndFlowEventArgs) {
484   const char* kCategory = "cat";
485   const char* kName = "name";
486 
487   TraceStorage* storage = context_.storage.get();
488 
489   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
490   TrackId track = context_.track_tracker->InternThreadTrack(utid);
491   context_.args_tracker->Flush();  // Flush track args.
492   StringId cat_id = storage->InternString(base::StringView(kCategory));
493   StringId name_id = storage->InternString(base::StringView(kName));
494   SliceId id1 = storage->mutable_slice_table()
495                     ->Insert({0, 0, track, cat_id, name_id, 0, 0, 0})
496                     .id;
497   SliceId id2 = storage->mutable_slice_table()
498                     ->Insert({100, 0, track, cat_id, name_id, 0, 0, 0})
499                     .id;
500 
501   storage->mutable_flow_table()->Insert({id1, id2, 0});
502 
503   base::TempFile temp_file = base::TempFile::Create();
504   FILE* output = fopen(temp_file.path().c_str(), "w+e");
505   base::Status status = ExportJson(storage, output);
506 
507   EXPECT_TRUE(status.ok());
508 
509   Json::Value result = ToJsonValue(ReadFile(output));
510   EXPECT_EQ(result["traceEvents"].size(), 4u);
511 
512   Json::Value slice_out = result["traceEvents"][0];
513   Json::Value slice_in = result["traceEvents"][1];
514   Json::Value flow_out = result["traceEvents"][2];
515   Json::Value flow_in = result["traceEvents"][3];
516 
517   EXPECT_EQ(flow_out["cat"].asString(), kCategory);
518   EXPECT_EQ(flow_out["name"].asString(), kName);
519   EXPECT_EQ(flow_out["ph"].asString(), "s");
520   EXPECT_EQ(flow_out["tid"].asString(), slice_out["tid"].asString());
521   EXPECT_EQ(flow_out["pid"].asString(), slice_out["pid"].asString());
522 
523   EXPECT_EQ(flow_in["cat"].asString(), kCategory);
524   EXPECT_EQ(flow_in["name"].asString(), kName);
525   EXPECT_EQ(flow_in["ph"].asString(), "f");
526   EXPECT_EQ(flow_in["bp"].asString(), "e");
527   EXPECT_EQ(flow_in["tid"].asString(), slice_in["tid"].asString());
528   EXPECT_EQ(flow_in["pid"].asString(), slice_in["pid"].asString());
529 
530   EXPECT_LE(slice_out["ts"].asInt64(), flow_out["ts"].asInt64());
531   EXPECT_GE(slice_in["ts"].asInt64(), flow_in["ts"].asInt64());
532 
533   EXPECT_EQ(flow_out["id"].asString(), flow_in["id"].asString());
534 }
535 
TEST_F(ExportJsonTest,StorageWithListArgs)536 TEST_F(ExportJsonTest, StorageWithListArgs) {
537   const char* kCategory = "cat";
538   const char* kName = "name";
539   double kValues[] = {1.234, 2.345};
540 
541   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
542   TrackId track = context_.track_tracker->InternThreadTrack(utid);
543   context_.args_tracker->Flush();  // Flush track args.
544   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
545   StringId name_id = context_.storage->InternString(base::StringView(kName));
546   context_.storage->mutable_slice_table()->Insert(
547       {0, 0, track, cat_id, name_id, 0, 0, 0});
548 
549   StringId arg_flat_key_id = context_.storage->InternString(
550       base::StringView("debug.draw_duration_ms"));
551   StringId arg_key0_id = context_.storage->InternString(
552       base::StringView("debug.draw_duration_ms[0]"));
553   StringId arg_key1_id = context_.storage->InternString(
554       base::StringView("debug.draw_duration_ms[1]"));
555   GlobalArgsTracker::Arg arg0;
556   arg0.flat_key = arg_flat_key_id;
557   arg0.key = arg_key0_id;
558   arg0.value = Variadic::Real(kValues[0]);
559   GlobalArgsTracker::Arg arg1;
560   arg1.flat_key = arg_flat_key_id;
561   arg1.key = arg_key1_id;
562   arg1.value = Variadic::Real(kValues[1]);
563   ArgSetId args = context_.global_args_tracker->AddArgSet({arg0, arg1}, 0, 2);
564   auto& slice = *context_.storage->mutable_slice_table();
565   slice[0].set_arg_set_id(args);
566 
567   base::TempFile temp_file = base::TempFile::Create();
568   FILE* output = fopen(temp_file.path().c_str(), "w+e");
569   base::Status status = ExportJson(context_.storage.get(), output);
570 
571   EXPECT_TRUE(status.ok());
572 
573   Json::Value result = ToJsonValue(ReadFile(output));
574   EXPECT_EQ(result["traceEvents"].size(), 1u);
575 
576   Json::Value event = result["traceEvents"][0];
577   EXPECT_EQ(event["cat"].asString(), kCategory);
578   EXPECT_EQ(event["name"].asString(), kName);
579   EXPECT_EQ(event["args"]["draw_duration_ms"].size(), 2u);
580   EXPECT_DOUBLE_EQ(event["args"]["draw_duration_ms"][0].asDouble(), kValues[0]);
581   EXPECT_DOUBLE_EQ(event["args"]["draw_duration_ms"][1].asDouble(), kValues[1]);
582 }
583 
TEST_F(ExportJsonTest,StorageWithMultiplePointerArgs)584 TEST_F(ExportJsonTest, StorageWithMultiplePointerArgs) {
585   const char* kCategory = "cat";
586   const char* kName = "name";
587   uint64_t kValue0 = 1;
588   uint64_t kValue1 = std::numeric_limits<uint64_t>::max();
589 
590   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
591   TrackId track = context_.track_tracker->InternThreadTrack(utid);
592   context_.args_tracker->Flush();  // Flush track args.
593   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
594   StringId name_id = context_.storage->InternString(base::StringView(kName));
595   context_.storage->mutable_slice_table()->Insert(
596       {0, 0, track, cat_id, name_id, 0, 0, 0});
597 
598   StringId arg_key0_id =
599       context_.storage->InternString(base::StringView("arg0"));
600   StringId arg_key1_id =
601       context_.storage->InternString(base::StringView("arg1"));
602   GlobalArgsTracker::Arg arg0;
603   arg0.flat_key = arg_key0_id;
604   arg0.key = arg_key0_id;
605   arg0.value = Variadic::Pointer(kValue0);
606   GlobalArgsTracker::Arg arg1;
607   arg1.flat_key = arg_key1_id;
608   arg1.key = arg_key1_id;
609   arg1.value = Variadic::Pointer(kValue1);
610   ArgSetId args = context_.global_args_tracker->AddArgSet({arg0, arg1}, 0, 2);
611   auto& slice = *context_.storage->mutable_slice_table();
612   slice[0].set_arg_set_id(args);
613 
614   base::TempFile temp_file = base::TempFile::Create();
615   FILE* output = fopen(temp_file.path().c_str(), "w+e");
616   base::Status status = ExportJson(context_.storage.get(), output);
617 
618   EXPECT_TRUE(status.ok());
619 
620   Json::Value result = ToJsonValue(ReadFile(output));
621   EXPECT_EQ(result["traceEvents"].size(), 1u);
622 
623   Json::Value event = result["traceEvents"][0];
624   EXPECT_EQ(event["cat"].asString(), kCategory);
625   EXPECT_EQ(event["name"].asString(), kName);
626   EXPECT_EQ(event["args"]["arg0"].asString(), "0x1");
627   EXPECT_EQ(event["args"]["arg1"].asString(), "0xffffffffffffffff");
628 }
629 
TEST_F(ExportJsonTest,StorageWithObjectListArgs)630 TEST_F(ExportJsonTest, StorageWithObjectListArgs) {
631   const char* kCategory = "cat";
632   const char* kName = "name";
633   int kValues[] = {123, 234};
634 
635   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
636   TrackId track = context_.track_tracker->InternThreadTrack(utid);
637   context_.args_tracker->Flush();  // Flush track args.
638   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
639   StringId name_id = context_.storage->InternString(base::StringView(kName));
640   context_.storage->mutable_slice_table()->Insert(
641       {0, 0, track, cat_id, name_id, 0, 0, 0});
642 
643   StringId arg_flat_key_id =
644       context_.storage->InternString(base::StringView("a.b"));
645   StringId arg_key0_id =
646       context_.storage->InternString(base::StringView("a[0].b"));
647   StringId arg_key1_id =
648       context_.storage->InternString(base::StringView("a[1].b"));
649   GlobalArgsTracker::Arg arg0;
650   arg0.flat_key = arg_flat_key_id;
651   arg0.key = arg_key0_id;
652   arg0.value = Variadic::Integer(kValues[0]);
653   GlobalArgsTracker::Arg arg1;
654   arg1.flat_key = arg_flat_key_id;
655   arg1.key = arg_key1_id;
656   arg1.value = Variadic::Integer(kValues[1]);
657   ArgSetId args = context_.global_args_tracker->AddArgSet({arg0, arg1}, 0, 2);
658   auto& slice = *context_.storage->mutable_slice_table();
659   slice[0].set_arg_set_id(args);
660 
661   base::TempFile temp_file = base::TempFile::Create();
662   FILE* output = fopen(temp_file.path().c_str(), "w+e");
663   base::Status status = ExportJson(context_.storage.get(), output);
664 
665   EXPECT_TRUE(status.ok());
666 
667   Json::Value result = ToJsonValue(ReadFile(output));
668   EXPECT_EQ(result["traceEvents"].size(), 1u);
669 
670   Json::Value event = result["traceEvents"][0];
671   EXPECT_EQ(event["cat"].asString(), kCategory);
672   EXPECT_EQ(event["name"].asString(), kName);
673   EXPECT_EQ(event["args"]["a"].size(), 2u);
674   EXPECT_EQ(event["args"]["a"][0]["b"].asInt(), kValues[0]);
675   EXPECT_EQ(event["args"]["a"][1]["b"].asInt(), kValues[1]);
676 }
677 
TEST_F(ExportJsonTest,StorageWithNestedListArgs)678 TEST_F(ExportJsonTest, StorageWithNestedListArgs) {
679   const char* kCategory = "cat";
680   const char* kName = "name";
681   int kValues[] = {123, 234};
682 
683   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
684   TrackId track = context_.track_tracker->InternThreadTrack(utid);
685   context_.args_tracker->Flush();  // Flush track args.
686   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
687   StringId name_id = context_.storage->InternString(base::StringView(kName));
688   context_.storage->mutable_slice_table()->Insert(
689       {0, 0, track, cat_id, name_id, 0, 0, 0});
690 
691   StringId arg_flat_key_id =
692       context_.storage->InternString(base::StringView("a"));
693   StringId arg_key0_id =
694       context_.storage->InternString(base::StringView("a[0][0]"));
695   StringId arg_key1_id =
696       context_.storage->InternString(base::StringView("a[0][1]"));
697   GlobalArgsTracker::Arg arg0;
698   arg0.flat_key = arg_flat_key_id;
699   arg0.key = arg_key0_id;
700   arg0.value = Variadic::Integer(kValues[0]);
701   GlobalArgsTracker::Arg arg1;
702   arg1.flat_key = arg_flat_key_id;
703   arg1.key = arg_key1_id;
704   arg1.value = Variadic::Integer(kValues[1]);
705   ArgSetId args = context_.global_args_tracker->AddArgSet({arg0, arg1}, 0, 2);
706   auto& slice = *context_.storage->mutable_slice_table();
707   slice[0].set_arg_set_id(args);
708 
709   base::TempFile temp_file = base::TempFile::Create();
710   FILE* output = fopen(temp_file.path().c_str(), "w+e");
711   base::Status status = ExportJson(context_.storage.get(), output);
712 
713   EXPECT_TRUE(status.ok());
714 
715   Json::Value result = ToJsonValue(ReadFile(output));
716   EXPECT_EQ(result["traceEvents"].size(), 1u);
717 
718   Json::Value event = result["traceEvents"][0];
719   EXPECT_EQ(event["cat"].asString(), kCategory);
720   EXPECT_EQ(event["name"].asString(), kName);
721   EXPECT_EQ(event["args"]["a"].size(), 1u);
722   EXPECT_EQ(event["args"]["a"][0].size(), 2u);
723   EXPECT_EQ(event["args"]["a"][0][0].asInt(), kValues[0]);
724   EXPECT_EQ(event["args"]["a"][0][1].asInt(), kValues[1]);
725 }
726 
TEST_F(ExportJsonTest,StorageWithLegacyJsonArgs)727 TEST_F(ExportJsonTest, StorageWithLegacyJsonArgs) {
728   const char* kCategory = "cat";
729   const char* kName = "name";
730 
731   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
732   TrackId track = context_.track_tracker->InternThreadTrack(utid);
733   context_.args_tracker->Flush();  // Flush track args.
734   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
735   StringId name_id = context_.storage->InternString(base::StringView(kName));
736   context_.storage->mutable_slice_table()->Insert(
737       {0, 0, track, cat_id, name_id, 0, 0, 0});
738 
739   StringId arg_key_id = context_.storage->InternString(base::StringView("a"));
740   StringId arg_value_id =
741       context_.storage->InternString(base::StringView("{\"b\":123}"));
742   GlobalArgsTracker::Arg arg;
743   arg.flat_key = arg_key_id;
744   arg.key = arg_key_id;
745   arg.value = Variadic::Json(arg_value_id);
746   ArgSetId args = context_.global_args_tracker->AddArgSet({arg}, 0, 1);
747   auto& slice = *context_.storage->mutable_slice_table();
748   slice[0].set_arg_set_id(args);
749 
750   base::TempFile temp_file = base::TempFile::Create();
751   FILE* output = fopen(temp_file.path().c_str(), "w+e");
752   base::Status status = ExportJson(context_.storage.get(), output);
753 
754   EXPECT_TRUE(status.ok());
755 
756   Json::Value result = ToJsonValue(ReadFile(output));
757   EXPECT_EQ(result["traceEvents"].size(), 1u);
758 
759   Json::Value event = result["traceEvents"][0];
760   EXPECT_EQ(event["cat"].asString(), kCategory);
761   EXPECT_EQ(event["name"].asString(), kName);
762   EXPECT_EQ(event["args"]["a"]["b"].asInt(), 123);
763 }
764 
TEST_F(ExportJsonTest,InstantEvent)765 TEST_F(ExportJsonTest, InstantEvent) {
766   const int64_t kTimestamp = 10000000;
767   const int64_t kTimestamp2 = 10001000;
768   const int64_t kTimestamp3 = 10002000;
769   const char* kCategory = "cat";
770   const char* kName = "name";
771 
772   // Global legacy track.
773   TrackId track = context_.track_tracker->InternTrack(
774       tracks::kLegacyGlobalInstantsBlueprint, tracks::Dimensions(),
775       tracks::BlueprintName(), [this](ArgsTracker::BoundInserter& inserter) {
776         inserter.AddArg(
777             context_.storage->InternString("source"),
778             Variadic::String(context_.storage->InternString("chrome")));
779       });
780   context_.args_tracker->Flush();  // Flush track args.
781   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
782   StringId name_id = context_.storage->InternString(base::StringView(kName));
783   context_.storage->mutable_slice_table()->Insert(
784       {kTimestamp, 0, track, cat_id, name_id, 0, 0, 0});
785 
786   // Global track.
787   TrackEventTracker track_event_tracker(&context_);
788   TrackId track2 = track_event_tracker.GetOrCreateDefaultDescriptorTrack();
789   context_.args_tracker->Flush();  // Flush track args.
790   context_.storage->mutable_slice_table()->Insert(
791       {kTimestamp2, 0, track2, cat_id, name_id, 0, 0, 0});
792 
793   // Async event track.
794   TrackEventTracker::DescriptorTrackReservation reservation;
795   reservation.parent_uuid = 0;
796   track_event_tracker.ReserveDescriptorTrack(1234, reservation);
797   TrackId track3 = *track_event_tracker.GetDescriptorTrack(1234);
798   context_.args_tracker->Flush();  // Flush track args.
799   context_.storage->mutable_slice_table()->Insert(
800       {kTimestamp3, 0, track3, cat_id, name_id, 0, 0, 0});
801 
802   base::TempFile temp_file = base::TempFile::Create();
803   FILE* output = fopen(temp_file.path().c_str(), "w+e");
804   base::Status status = ExportJson(context_.storage.get(), output);
805 
806   EXPECT_TRUE(status.ok());
807 
808   Json::Value result = ToJsonValue(ReadFile(output));
809   EXPECT_EQ(result["traceEvents"].size(), 3u);
810 
811   Json::Value event = result["traceEvents"][0];
812   EXPECT_EQ(event["ph"].asString(), "I");
813   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
814   EXPECT_EQ(event["s"].asString(), "g");
815   EXPECT_EQ(event["cat"].asString(), kCategory);
816   EXPECT_EQ(event["name"].asString(), kName);
817 
818   Json::Value event2 = result["traceEvents"][1];
819   EXPECT_EQ(event2["ph"].asString(), "I");
820   EXPECT_EQ(event2["ts"].asInt64(), kTimestamp2 / 1000);
821   EXPECT_EQ(event2["s"].asString(), "g");
822   EXPECT_EQ(event2["cat"].asString(), kCategory);
823   EXPECT_EQ(event2["name"].asString(), kName);
824 
825   Json::Value event3 = result["traceEvents"][2];
826   EXPECT_EQ(event3["ph"].asString(), "n");
827   EXPECT_EQ(event3["ts"].asInt64(), kTimestamp3 / 1000);
828   EXPECT_EQ(event3["id"].asString(), "0x2");
829   EXPECT_EQ(event3["cat"].asString(), kCategory);
830   EXPECT_EQ(event3["name"].asString(), kName);
831 }
832 
TEST_F(ExportJsonTest,InstantEventOnThread)833 TEST_F(ExportJsonTest, InstantEventOnThread) {
834   const int64_t kTimestamp = 10000000;
835   const uint32_t kThreadID = 100;
836   const char* kCategory = "cat";
837   const char* kName = "name";
838 
839   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
840   TrackId track = context_.track_tracker->InternThreadTrack(utid);
841   context_.args_tracker->Flush();  // Flush track args.
842   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
843   StringId name_id = context_.storage->InternString(base::StringView(kName));
844   context_.storage->mutable_slice_table()->Insert(
845       {kTimestamp, 0, track, cat_id, name_id, 0, 0, 0});
846 
847   base::TempFile temp_file = base::TempFile::Create();
848   FILE* output = fopen(temp_file.path().c_str(), "w+e");
849   base::Status status = ExportJson(context_.storage.get(), output);
850 
851   EXPECT_TRUE(status.ok());
852 
853   Json::Value result = ToJsonValue(ReadFile(output));
854   EXPECT_EQ(result["traceEvents"].size(), 1u);
855 
856   Json::Value event = result["traceEvents"][0];
857   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
858   EXPECT_EQ(event["ph"].asString(), "I");
859   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
860   EXPECT_EQ(event["s"].asString(), "t");
861   EXPECT_EQ(event["cat"].asString(), kCategory);
862   EXPECT_EQ(event["name"].asString(), kName);
863 }
864 
TEST_F(ExportJsonTest,DuplicatePidAndTid)865 TEST_F(ExportJsonTest, DuplicatePidAndTid) {
866   UniqueTid upid1 = context_.process_tracker->StartNewProcess(
867       std::nullopt, std::nullopt, 1, kNullStringId,
868       ThreadNamePriority::kTrackDescriptor);
869   UniqueTid utid1a = context_.process_tracker->UpdateThread(1, 1);
870   UniqueTid utid1b = context_.process_tracker->UpdateThread(2, 1);
871   UniqueTid utid1c = context_.process_tracker->StartNewThread(std::nullopt, 2);
872   // Associate the new thread with its process.
873   ASSERT_EQ(utid1c, context_.process_tracker->UpdateThread(2, 1));
874 
875   UniqueTid upid2 = context_.process_tracker->StartNewProcess(
876       std::nullopt, std::nullopt, 1, kNullStringId,
877       ThreadNamePriority::kTrackDescriptor);
878   UniqueTid utid2a = context_.process_tracker->UpdateThread(1, 1);
879   UniqueTid utid2b = context_.process_tracker->UpdateThread(2, 1);
880 
881   ASSERT_NE(upid1, upid2);
882   ASSERT_NE(utid1b, utid1c);
883   ASSERT_NE(utid1a, utid2a);
884   ASSERT_NE(utid1b, utid2b);
885   ASSERT_NE(utid1c, utid2b);
886 
887   const auto& thread_table = context_.storage->thread_table();
888   ASSERT_EQ(upid1, *thread_table[utid1a].upid());
889   ASSERT_EQ(upid1, *thread_table[utid1b].upid());
890   ASSERT_EQ(upid1, *thread_table[utid1c].upid());
891   ASSERT_EQ(upid2, *thread_table[utid2a].upid());
892   ASSERT_EQ(upid2, *thread_table[utid2b].upid());
893 
894   TrackId track1a = context_.track_tracker->InternThreadTrack(utid1a);
895   TrackId track1b = context_.track_tracker->InternThreadTrack(utid1b);
896   TrackId track1c = context_.track_tracker->InternThreadTrack(utid1c);
897   TrackId track2a = context_.track_tracker->InternThreadTrack(utid2a);
898   TrackId track2b = context_.track_tracker->InternThreadTrack(utid2b);
899   context_.args_tracker->Flush();  // Flush track args.
900 
901   StringId cat_id = context_.storage->InternString(base::StringView("cat"));
902   StringId name1a_id =
903       context_.storage->InternString(base::StringView("name1a"));
904   StringId name1b_id =
905       context_.storage->InternString(base::StringView("name1b"));
906   StringId name1c_id =
907       context_.storage->InternString(base::StringView("name1c"));
908   StringId name2a_id =
909       context_.storage->InternString(base::StringView("name2a"));
910   StringId name2b_id =
911       context_.storage->InternString(base::StringView("name2b"));
912 
913   context_.storage->mutable_slice_table()->Insert(
914       {10000, 0, track1a, cat_id, name1a_id, 0, 0, 0});
915   context_.storage->mutable_slice_table()->Insert(
916       {20000, 1000, track1b, cat_id, name1b_id, 0, 0, 0});
917   context_.storage->mutable_slice_table()->Insert(
918       {30000, 0, track1c, cat_id, name1c_id, 0, 0, 0});
919   context_.storage->mutable_slice_table()->Insert(
920       {40000, 0, track2a, cat_id, name2a_id, 0, 0, 0});
921   context_.storage->mutable_slice_table()->Insert(
922       {50000, 1000, track2b, cat_id, name2b_id, 0, 0, 0});
923 
924   base::TempFile temp_file = base::TempFile::Create();
925   FILE* output = fopen(temp_file.path().c_str(), "w+e");
926   base::Status status = ExportJson(context_.storage.get(), output);
927 
928   EXPECT_TRUE(status.ok());
929 
930   Json::Value result = ToJsonValue(ReadFile(output));
931   EXPECT_EQ(result["traceEvents"].size(), 5u);
932 
933   EXPECT_EQ(result["traceEvents"][0]["pid"].asInt(), 1);
934   EXPECT_EQ(result["traceEvents"][0]["tid"].asInt(), 1);
935   EXPECT_EQ(result["traceEvents"][0]["ph"].asString(), "I");
936   EXPECT_EQ(result["traceEvents"][0]["ts"].asInt64(), 10);
937   EXPECT_EQ(result["traceEvents"][0]["cat"].asString(), "cat");
938   EXPECT_EQ(result["traceEvents"][0]["name"].asString(), "name1a");
939 
940   EXPECT_EQ(result["traceEvents"][1]["pid"].asInt(), 1);
941   EXPECT_EQ(result["traceEvents"][1]["tid"].asInt(), 2);
942   EXPECT_EQ(result["traceEvents"][1]["ph"].asString(), "X");
943   EXPECT_EQ(result["traceEvents"][1]["ts"].asInt64(), 20);
944   EXPECT_EQ(result["traceEvents"][1]["dur"].asInt64(), 1);
945   EXPECT_EQ(result["traceEvents"][1]["cat"].asString(), "cat");
946   EXPECT_EQ(result["traceEvents"][1]["name"].asString(), "name1b");
947 
948   EXPECT_EQ(result["traceEvents"][2]["pid"].asInt(), 1);
949   EXPECT_EQ(result["traceEvents"][2]["tid"].asInt(),
950             static_cast<int>(std::numeric_limits<uint32_t>::max() - 1u));
951   EXPECT_EQ(result["traceEvents"][2]["ph"].asString(), "I");
952   EXPECT_EQ(result["traceEvents"][2]["ts"].asInt64(), 30);
953   EXPECT_EQ(result["traceEvents"][2]["cat"].asString(), "cat");
954   EXPECT_EQ(result["traceEvents"][2]["name"].asString(), "name1c");
955 
956   EXPECT_EQ(result["traceEvents"][3]["pid"].asInt(),
957             static_cast<int>(std::numeric_limits<uint32_t>::max()));
958   EXPECT_EQ(result["traceEvents"][3]["tid"].asInt(), 1);
959   EXPECT_EQ(result["traceEvents"][3]["ph"].asString(), "I");
960   EXPECT_EQ(result["traceEvents"][3]["ts"].asInt64(), 40);
961   EXPECT_EQ(result["traceEvents"][3]["cat"].asString(), "cat");
962   EXPECT_EQ(result["traceEvents"][3]["name"].asString(), "name2a");
963 
964   EXPECT_EQ(result["traceEvents"][4]["pid"].asInt(),
965             static_cast<int>(std::numeric_limits<uint32_t>::max()));
966   EXPECT_EQ(result["traceEvents"][4]["tid"].asInt(), 2);
967   EXPECT_EQ(result["traceEvents"][4]["ph"].asString(), "X");
968   EXPECT_EQ(result["traceEvents"][4]["ts"].asInt64(), 50);
969   EXPECT_EQ(result["traceEvents"][1]["dur"].asInt64(), 1);
970   EXPECT_EQ(result["traceEvents"][4]["cat"].asString(), "cat");
971   EXPECT_EQ(result["traceEvents"][4]["name"].asString(), "name2b");
972 }
973 
TEST_F(ExportJsonTest,AsyncEvents)974 TEST_F(ExportJsonTest, AsyncEvents) {
975   const int64_t kTimestamp = 10000000;
976   const int64_t kDuration = 100000;
977   const int64_t kTimestamp3 = 10005000;
978   const int64_t kDuration3 = 100000;
979   const uint32_t kProcessID = 100;
980   const char* kCategory = "cat";
981   const char* kName = "name";
982   const char* kName2 = "name2";
983   const char* kName3 = "name3";
984   const char* kArgName = "arg_name";
985   const int kArgValue = 123;
986 
987   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
988   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
989   StringId name_id = context_.storage->InternString(base::StringView(kName));
990   StringId name2_id = context_.storage->InternString(base::StringView(kName2));
991   StringId name3_id = context_.storage->InternString(base::StringView(kName3));
992 
993   constexpr int64_t kSourceId = 235;
994   TrackId track = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
995       name_id, upid, kSourceId, /*trace_id_is_process_scoped=*/true,
996       /*source_scope=*/kNullStringId);
997   constexpr int64_t kSourceId2 = 236;
998   TrackId track2 = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
999       name3_id, upid, kSourceId2, /*trace_id_is_process_scoped=*/true,
1000       /*source_scope=*/kNullStringId);
1001   context_.args_tracker->Flush();  // Flush track args.
1002 
1003   context_.storage->mutable_slice_table()->Insert(
1004       {kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0});
1005   StringId arg_key_id =
1006       context_.storage->InternString(base::StringView(kArgName));
1007   GlobalArgsTracker::Arg arg;
1008   arg.flat_key = arg_key_id;
1009   arg.key = arg_key_id;
1010   arg.value = Variadic::Integer(kArgValue);
1011   ArgSetId args = context_.global_args_tracker->AddArgSet({arg}, 0, 1);
1012   auto& slice = *context_.storage->mutable_slice_table();
1013   slice[0].set_arg_set_id(args);
1014 
1015   // Child event with same timestamps as first one.
1016   context_.storage->mutable_slice_table()->Insert(
1017       {kTimestamp, kDuration, track, cat_id, name2_id, 0, 0, 0});
1018 
1019   // Another overlapping async event on a different track.
1020   context_.storage->mutable_slice_table()->Insert(
1021       {kTimestamp3, kDuration3, track2, cat_id, name3_id, 0, 0, 0});
1022 
1023   base::TempFile temp_file = base::TempFile::Create();
1024   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1025   base::Status status = ExportJson(context_.storage.get(), output);
1026 
1027   EXPECT_TRUE(status.ok());
1028 
1029   Json::Value result = ToJsonValue(ReadFile(output));
1030   EXPECT_EQ(result["traceEvents"].size(), 6u);
1031 
1032   // Events should be sorted by timestamp, with child slice's end before its
1033   // parent.
1034 
1035   Json::Value begin_event1 = result["traceEvents"][0];
1036   EXPECT_EQ(begin_event1["ph"].asString(), "b");
1037   EXPECT_EQ(begin_event1["ts"].asInt64(), kTimestamp / 1000);
1038   EXPECT_EQ(begin_event1["pid"].asInt(), static_cast<int>(kProcessID));
1039   EXPECT_EQ(begin_event1["id2"]["local"].asString(), "0xeb");
1040   EXPECT_EQ(begin_event1["cat"].asString(), kCategory);
1041   EXPECT_EQ(begin_event1["name"].asString(), kName);
1042   EXPECT_EQ(begin_event1["args"][kArgName].asInt(), kArgValue);
1043   EXPECT_FALSE(begin_event1.isMember("tts"));
1044   EXPECT_FALSE(begin_event1.isMember("use_async_tts"));
1045 
1046   Json::Value begin_event2 = result["traceEvents"][1];
1047   EXPECT_EQ(begin_event2["ph"].asString(), "b");
1048   EXPECT_EQ(begin_event2["ts"].asInt64(), kTimestamp / 1000);
1049   EXPECT_EQ(begin_event2["pid"].asInt(), static_cast<int>(kProcessID));
1050   EXPECT_EQ(begin_event2["id2"]["local"].asString(), "0xeb");
1051   EXPECT_EQ(begin_event2["cat"].asString(), kCategory);
1052   EXPECT_EQ(begin_event2["name"].asString(), kName2);
1053   EXPECT_TRUE(begin_event2["args"].isObject());
1054   EXPECT_EQ(begin_event2["args"].size(), 0u);
1055   EXPECT_FALSE(begin_event2.isMember("tts"));
1056   EXPECT_FALSE(begin_event2.isMember("use_async_tts"));
1057 
1058   Json::Value begin_event3 = result["traceEvents"][2];
1059   EXPECT_EQ(begin_event3["ph"].asString(), "b");
1060   EXPECT_EQ(begin_event3["ts"].asInt64(), kTimestamp3 / 1000);
1061   EXPECT_EQ(begin_event3["pid"].asInt(), static_cast<int>(kProcessID));
1062   EXPECT_EQ(begin_event3["id2"]["local"].asString(), "0xec");
1063   EXPECT_EQ(begin_event3["cat"].asString(), kCategory);
1064   EXPECT_EQ(begin_event3["name"].asString(), kName3);
1065   EXPECT_TRUE(begin_event3["args"].isObject());
1066   EXPECT_EQ(begin_event3["args"].size(), 0u);
1067   EXPECT_FALSE(begin_event3.isMember("tts"));
1068   EXPECT_FALSE(begin_event3.isMember("use_async_tts"));
1069 
1070   Json::Value end_event2 = result["traceEvents"][3];
1071   EXPECT_EQ(end_event2["ph"].asString(), "e");
1072   EXPECT_EQ(end_event2["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
1073   EXPECT_EQ(end_event2["pid"].asInt(), static_cast<int>(kProcessID));
1074   EXPECT_EQ(end_event2["id2"]["local"].asString(), "0xeb");
1075   EXPECT_EQ(end_event2["cat"].asString(), kCategory);
1076   EXPECT_EQ(end_event2["name"].asString(), kName2);
1077   EXPECT_TRUE(end_event2["args"].isObject());
1078   EXPECT_EQ(end_event2["args"].size(), 0u);
1079   EXPECT_FALSE(end_event2.isMember("tts"));
1080   EXPECT_FALSE(end_event2.isMember("use_async_tts"));
1081 
1082   Json::Value end_event1 = result["traceEvents"][4];
1083   EXPECT_EQ(end_event1["ph"].asString(), "e");
1084   EXPECT_EQ(end_event1["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
1085   EXPECT_EQ(end_event1["pid"].asInt(), static_cast<int>(kProcessID));
1086   EXPECT_EQ(end_event1["id2"]["local"].asString(), "0xeb");
1087   EXPECT_EQ(end_event1["cat"].asString(), kCategory);
1088   EXPECT_EQ(end_event1["name"].asString(), kName);
1089   EXPECT_TRUE(end_event1["args"].isObject());
1090   EXPECT_EQ(end_event1["args"].size(), 0u);
1091   EXPECT_FALSE(end_event1.isMember("tts"));
1092   EXPECT_FALSE(end_event1.isMember("use_async_tts"));
1093 
1094   Json::Value end_event3 = result["traceEvents"][5];
1095   EXPECT_EQ(end_event3["ph"].asString(), "e");
1096   EXPECT_EQ(end_event3["ts"].asInt64(), (kTimestamp3 + kDuration3) / 1000);
1097   EXPECT_EQ(end_event3["pid"].asInt(), static_cast<int>(kProcessID));
1098   EXPECT_EQ(end_event3["id2"]["local"].asString(), "0xec");
1099   EXPECT_EQ(end_event3["cat"].asString(), kCategory);
1100   EXPECT_EQ(end_event3["name"].asString(), kName3);
1101   EXPECT_TRUE(end_event3["args"].isObject());
1102   EXPECT_EQ(end_event3["args"].size(), 0u);
1103   EXPECT_FALSE(end_event3.isMember("tts"));
1104   EXPECT_FALSE(end_event3.isMember("use_async_tts"));
1105 }
1106 
TEST_F(ExportJsonTest,LegacyAsyncEvents)1107 TEST_F(ExportJsonTest, LegacyAsyncEvents) {
1108   using Arg = GlobalArgsTracker::Arg;
1109   const int64_t kTimestamp = 10000000;
1110   const int64_t kDuration = 100000;
1111   const int64_t kTimestamp2 = 10001000;
1112   const int64_t kDuration2 = 0;
1113   const int64_t kTimestamp3 = 10005000;
1114   const int64_t kDuration3 = 100000;
1115   const uint32_t kProcessID = 100;
1116   const char* kCategory = "cat";
1117   const char* kName = "name";
1118   const char* kName2 = "name2";
1119   const char* kName3 = "name3";
1120 
1121   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1122   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
1123   StringId name_id = context_.storage->InternString(base::StringView(kName));
1124   StringId name2_id = context_.storage->InternString(base::StringView(kName2));
1125   StringId name3_id = context_.storage->InternString(base::StringView(kName3));
1126 
1127   auto arg_inserter = [this](base::StringView arg_name,
1128                              base::StringView arg_value,
1129                              std::vector<Arg>& args) {
1130     Arg arg;
1131     StringId arg_key_id =
1132         context_.storage->InternString(base::StringView(arg_name));
1133     arg.flat_key = arg_key_id;
1134     arg.key = arg_key_id;
1135     StringId value_id = context_.storage->InternString(arg_value);
1136     arg.value = Variadic::String(value_id);
1137     args.push_back(arg);
1138   };
1139 
1140   constexpr int64_t kSourceId = 235;
1141   TrackId track = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
1142       name_id, upid, kSourceId, /*trace_id_is_process_scoped=*/true,
1143       /*source_scope=*/kNullStringId);
1144   constexpr int64_t kSourceId2 = 236;
1145   TrackId track2 = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
1146       name3_id, upid, kSourceId2, /*trace_id_is_process_scoped=*/true,
1147       /*source_scope=*/kNullStringId);
1148   context_.args_tracker->Flush();  // Flush track args.
1149 
1150   context_.storage->mutable_slice_table()->Insert(
1151       {kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0});
1152   std::vector<Arg> args1;
1153   arg_inserter("arg1", "value1", args1);
1154   arg_inserter("legacy_event.phase", "S", args1);
1155   ArgSetId arg_id1 = context_.global_args_tracker->AddArgSet(args1, 0, 2);
1156   auto& slice = *context_.storage->mutable_slice_table();
1157   slice[0].set_arg_set_id(arg_id1);
1158 
1159   // Step event with first event as parent.
1160   context_.storage->mutable_slice_table()->Insert(
1161       {kTimestamp2, kDuration2, track, cat_id, name2_id, 0, 0, 0});
1162   std::vector<Arg> step_args;
1163   arg_inserter("arg2", "value2", step_args);
1164   arg_inserter("legacy_event.phase", "T", step_args);
1165   arg_inserter("debug.step", "Step1", step_args);
1166   ArgSetId arg_id2 = context_.global_args_tracker->AddArgSet(step_args, 0, 3);
1167   slice[1].set_arg_set_id(arg_id2);
1168 
1169   // Another overlapping async event on a different track.
1170   context_.storage->mutable_slice_table()->Insert(
1171       {kTimestamp3, kDuration3, track2, cat_id, name3_id, 0, 0, 0});
1172   std::vector<Arg> args3;
1173   arg_inserter("legacy_event.phase", "S", args3);
1174   ArgSetId arg_id3 = context_.global_args_tracker->AddArgSet(args3, 0, 1);
1175   slice[2].set_arg_set_id(arg_id3);
1176 
1177   base::TempFile temp_file = base::TempFile::Create();
1178   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1179   base::Status status = ExportJson(context_.storage.get(), output);
1180 
1181   EXPECT_TRUE(status.ok());
1182 
1183   Json::Value result = ToJsonValue(ReadFile(output));
1184   EXPECT_EQ(result["traceEvents"].size(), 5u);
1185 
1186   // Events should be sorted by timestamp, with child slice's end before its
1187   // parent.
1188 
1189   Json::Value begin_event1 = result["traceEvents"][0];
1190   EXPECT_EQ(begin_event1["ph"].asString(), "S");
1191   EXPECT_EQ(begin_event1["ts"].asInt64(), kTimestamp / 1000);
1192   EXPECT_EQ(begin_event1["pid"].asInt(), static_cast<int>(kProcessID));
1193   EXPECT_EQ(begin_event1["id2"]["local"].asString(), "0xeb");
1194   EXPECT_EQ(begin_event1["cat"].asString(), kCategory);
1195   EXPECT_EQ(begin_event1["name"].asString(), kName);
1196   EXPECT_FALSE(begin_event1.isMember("tts"));
1197   EXPECT_FALSE(begin_event1.isMember("use_async_tts"));
1198   EXPECT_EQ(begin_event1["args"].size(), 1u);
1199   EXPECT_EQ(begin_event1["args"]["arg1"].asString(), "value1");
1200 
1201   Json::Value step_event = result["traceEvents"][1];
1202   EXPECT_EQ(step_event["ph"].asString(), "T");
1203   EXPECT_EQ(step_event["ts"].asInt64(), kTimestamp2 / 1000);
1204   EXPECT_EQ(step_event["pid"].asInt(), static_cast<int>(kProcessID));
1205   EXPECT_EQ(step_event["id2"]["local"].asString(), "0xeb");
1206   EXPECT_EQ(step_event["cat"].asString(), kCategory);
1207   EXPECT_EQ(step_event["name"].asString(), kName2);
1208   EXPECT_TRUE(step_event["args"].isObject());
1209   EXPECT_EQ(step_event["args"].size(), 2u);
1210   EXPECT_EQ(step_event["args"]["arg2"].asString(), "value2");
1211   EXPECT_EQ(step_event["args"]["step"].asString(), "Step1");
1212 
1213   Json::Value begin_event2 = result["traceEvents"][2];
1214   EXPECT_EQ(begin_event2["ph"].asString(), "S");
1215   EXPECT_EQ(begin_event2["ts"].asInt64(), kTimestamp3 / 1000);
1216   EXPECT_EQ(begin_event2["pid"].asInt(), static_cast<int>(kProcessID));
1217   EXPECT_EQ(begin_event2["id2"]["local"].asString(), "0xec");
1218   EXPECT_EQ(begin_event2["cat"].asString(), kCategory);
1219   EXPECT_EQ(begin_event2["name"].asString(), kName3);
1220   EXPECT_TRUE(begin_event2["args"].isObject());
1221   EXPECT_EQ(begin_event2["args"].size(), 0u);
1222   EXPECT_FALSE(begin_event2.isMember("tts"));
1223   EXPECT_FALSE(begin_event2.isMember("use_async_tts"));
1224 
1225   Json::Value end_event1 = result["traceEvents"][3];
1226   EXPECT_EQ(end_event1["ph"].asString(), "F");
1227   EXPECT_EQ(end_event1["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
1228   EXPECT_EQ(end_event1["pid"].asInt(), static_cast<int>(kProcessID));
1229   EXPECT_EQ(end_event1["id2"]["local"].asString(), "0xeb");
1230   EXPECT_EQ(end_event1["cat"].asString(), kCategory);
1231   EXPECT_EQ(end_event1["name"].asString(), kName);
1232   EXPECT_TRUE(end_event1["args"].isObject());
1233   EXPECT_EQ(end_event1["args"].size(), 0u);
1234   EXPECT_FALSE(end_event1.isMember("tts"));
1235   EXPECT_FALSE(end_event1.isMember("use_async_tts"));
1236 
1237   Json::Value end_event3 = result["traceEvents"][4];
1238   EXPECT_EQ(end_event3["ph"].asString(), "F");
1239   EXPECT_EQ(end_event3["ts"].asInt64(), (kTimestamp3 + kDuration3) / 1000);
1240   EXPECT_EQ(end_event3["pid"].asInt(), static_cast<int>(kProcessID));
1241   EXPECT_EQ(end_event3["id2"]["local"].asString(), "0xec");
1242   EXPECT_EQ(end_event3["cat"].asString(), kCategory);
1243   EXPECT_EQ(end_event3["name"].asString(), kName3);
1244   EXPECT_TRUE(end_event3["args"].isObject());
1245   EXPECT_EQ(end_event3["args"].size(), 0u);
1246   EXPECT_FALSE(end_event3.isMember("tts"));
1247   EXPECT_FALSE(end_event3.isMember("use_async_tts"));
1248 }
1249 
TEST_F(ExportJsonTest,AsyncEventWithThreadTimestamp)1250 TEST_F(ExportJsonTest, AsyncEventWithThreadTimestamp) {
1251   const int64_t kTimestamp = 10000000;
1252   const int64_t kDuration = 100000;
1253   const int64_t kThreadTimestamp = 10000001;
1254   const int64_t kThreadDuration = 99998;
1255   const uint32_t kProcessID = 100;
1256   const char* kCategory = "cat";
1257   const char* kName = "name";
1258 
1259   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1260   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
1261   StringId name_id = context_.storage->InternString(base::StringView(kName));
1262 
1263   constexpr int64_t kSourceId = 235;
1264   TrackId track = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
1265       name_id, upid, kSourceId, /*trace_id_is_process_scoped=*/true,
1266       /*source_scope=*/kNullStringId);
1267   context_.args_tracker->Flush();  // Flush track args.
1268 
1269   auto* slices = context_.storage->mutable_slice_table();
1270   auto id_and_row =
1271       slices->Insert({kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0});
1272   context_.storage->mutable_virtual_track_slices()->AddVirtualTrackSlice(
1273       id_and_row.id, kThreadTimestamp, kThreadDuration, 0, 0);
1274 
1275   base::TempFile temp_file = base::TempFile::Create();
1276   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1277   base::Status status = ExportJson(context_.storage.get(), output);
1278 
1279   EXPECT_TRUE(status.ok());
1280 
1281   Json::Value result = ToJsonValue(ReadFile(output));
1282   EXPECT_EQ(result["traceEvents"].size(), 2u);
1283 
1284   Json::Value begin_event = result["traceEvents"][0];
1285   EXPECT_EQ(begin_event["ph"].asString(), "b");
1286   EXPECT_EQ(begin_event["ts"].asInt64(), kTimestamp / 1000);
1287   EXPECT_EQ(begin_event["tts"].asInt64(), kThreadTimestamp / 1000);
1288   EXPECT_EQ(begin_event["use_async_tts"].asInt(), 1);
1289   EXPECT_EQ(begin_event["pid"].asInt(), static_cast<int>(kProcessID));
1290   EXPECT_EQ(begin_event["id2"]["local"].asString(), "0xeb");
1291   EXPECT_EQ(begin_event["cat"].asString(), kCategory);
1292   EXPECT_EQ(begin_event["name"].asString(), kName);
1293 
1294   Json::Value end_event = result["traceEvents"][1];
1295   EXPECT_EQ(end_event["ph"].asString(), "e");
1296   EXPECT_EQ(end_event["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
1297   EXPECT_EQ(end_event["tts"].asInt64(),
1298             (kThreadTimestamp + kThreadDuration) / 1000);
1299   EXPECT_EQ(end_event["use_async_tts"].asInt(), 1);
1300   EXPECT_EQ(end_event["pid"].asInt(), static_cast<int>(kProcessID));
1301   EXPECT_EQ(end_event["id2"]["local"].asString(), "0xeb");
1302   EXPECT_EQ(end_event["cat"].asString(), kCategory);
1303   EXPECT_EQ(end_event["name"].asString(), kName);
1304 }
1305 
TEST_F(ExportJsonTest,UnfinishedAsyncEvent)1306 TEST_F(ExportJsonTest, UnfinishedAsyncEvent) {
1307   const int64_t kTimestamp = 10000000;
1308   const int64_t kDuration = -1;
1309   const int64_t kThreadTimestamp = 10000001;
1310   const int64_t kThreadDuration = -1;
1311   const uint32_t kProcessID = 100;
1312   const char* kCategory = "cat";
1313   const char* kName = "name";
1314 
1315   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1316   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
1317   StringId name_id = context_.storage->InternString(base::StringView(kName));
1318 
1319   constexpr int64_t kSourceId = 235;
1320   TrackId track = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
1321       name_id, upid, kSourceId, /*trace_id_is_process_scoped=*/true,
1322       /*source_scope=*/kNullStringId);
1323   context_.args_tracker->Flush();  // Flush track args.
1324 
1325   auto slice_id =
1326       context_.storage->mutable_slice_table()
1327           ->Insert({kTimestamp, kDuration, track, cat_id, name_id, 0, 0, 0})
1328           .id;
1329   context_.storage->mutable_virtual_track_slices()->AddVirtualTrackSlice(
1330       slice_id, kThreadTimestamp, kThreadDuration, 0, 0);
1331 
1332   base::TempFile temp_file = base::TempFile::Create();
1333   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1334   base::Status status = ExportJson(context_.storage.get(), output);
1335 
1336   EXPECT_TRUE(status.ok());
1337 
1338   Json::Value result = ToJsonValue(ReadFile(output));
1339   EXPECT_EQ(result["traceEvents"].size(), 1u);
1340 
1341   Json::Value begin_event = result["traceEvents"][0];
1342   EXPECT_EQ(begin_event["ph"].asString(), "b");
1343   EXPECT_EQ(begin_event["ts"].asInt64(), kTimestamp / 1000);
1344   EXPECT_EQ(begin_event["tts"].asInt64(), kThreadTimestamp / 1000);
1345   EXPECT_EQ(begin_event["use_async_tts"].asInt(), 1);
1346   EXPECT_EQ(begin_event["pid"].asInt(), static_cast<int>(kProcessID));
1347   EXPECT_EQ(begin_event["id2"]["local"].asString(), "0xeb");
1348   EXPECT_EQ(begin_event["cat"].asString(), kCategory);
1349   EXPECT_EQ(begin_event["name"].asString(), kName);
1350 }
1351 
TEST_F(ExportJsonTest,AsyncInstantEvent)1352 TEST_F(ExportJsonTest, AsyncInstantEvent) {
1353   const int64_t kTimestamp = 10000000;
1354   const uint32_t kProcessID = 100;
1355   const char* kCategory = "cat";
1356   const char* kName = "name";
1357   const char* kArgName = "arg_name";
1358   const int kArgValue = 123;
1359 
1360   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1361   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
1362   StringId name_id = context_.storage->InternString(base::StringView(kName));
1363 
1364   constexpr int64_t kSourceId = 235;
1365   TrackId track = context_.track_tracker->LegacyInternLegacyChromeAsyncTrack(
1366       name_id, upid, kSourceId, /*trace_id_is_process_scoped=*/true,
1367       /*source_scope=*/kNullStringId);
1368   context_.args_tracker->Flush();  // Flush track args.
1369 
1370   context_.storage->mutable_slice_table()->Insert(
1371       {kTimestamp, 0, track, cat_id, name_id, 0, 0, 0});
1372   StringId arg_key_id =
1373       context_.storage->InternString(base::StringView("arg_name"));
1374   GlobalArgsTracker::Arg arg;
1375   arg.flat_key = arg_key_id;
1376   arg.key = arg_key_id;
1377   arg.value = Variadic::Integer(kArgValue);
1378   ArgSetId args = context_.global_args_tracker->AddArgSet({arg}, 0, 1);
1379   auto& slice = *context_.storage->mutable_slice_table();
1380   slice[0].set_arg_set_id(args);
1381 
1382   base::TempFile temp_file = base::TempFile::Create();
1383   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1384   base::Status status = ExportJson(context_.storage.get(), output);
1385 
1386   EXPECT_TRUE(status.ok());
1387 
1388   Json::Value result = ToJsonValue(ReadFile(output));
1389   EXPECT_EQ(result["traceEvents"].size(), 1u);
1390 
1391   Json::Value event = result["traceEvents"][0];
1392   EXPECT_EQ(event["ph"].asString(), "n");
1393   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
1394   EXPECT_EQ(event["pid"].asInt(), static_cast<int>(kProcessID));
1395   EXPECT_EQ(event["id2"]["local"].asString(), "0xeb");
1396   EXPECT_EQ(event["cat"].asString(), kCategory);
1397   EXPECT_EQ(event["name"].asString(), kName);
1398   EXPECT_EQ(event["args"][kArgName].asInt(), kArgValue);
1399 }
1400 
TEST_F(ExportJsonTest,RawEvent)1401 TEST_F(ExportJsonTest, RawEvent) {
1402   const int64_t kTimestamp = 10000000;
1403   const int64_t kDuration = 10000;
1404   const int64_t kThreadTimestamp = 20000000;
1405   const int64_t kThreadDuration = 20000;
1406   const int64_t kThreadInstructionCount = 30000000;
1407   const int64_t kThreadInstructionDelta = 30000;
1408   const uint32_t kProcessID = 100;
1409   const uint32_t kThreadID = 200;
1410   const char* kCategory = "cat";
1411   const char* kName = "name";
1412   const char* kPhase = "?";
1413   const uint64_t kGlobalId = 0xaaffaaffaaffaaff;
1414   const char* kIdScope = "my_id";
1415   const uint64_t kBindId = 0xaa00aa00aa00aa00;
1416   const char* kFlowDirection = "inout";
1417   const char* kArgName = "arg_name";
1418   const int kArgValue = 123;
1419 
1420   TraceStorage* storage = context_.storage.get();
1421 
1422   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
1423   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1424 
1425   auto& tt = *context_.storage->mutable_thread_table();
1426   tt[utid].set_upid(upid);
1427 
1428   auto ucpu = context_.cpu_tracker->GetOrCreateCpu(0);
1429   auto id_and_row = storage->mutable_raw_table()->Insert(
1430       {kTimestamp, storage->InternString("track_event.legacy_event"), utid, 0,
1431        0, ucpu});
1432   auto inserter = context_.args_tracker->AddArgsTo(id_and_row.id);
1433 
1434   auto add_arg = [&](const char* key, Variadic value) {
1435     StringId key_id = storage->InternString(key);
1436     inserter.AddArg(key_id, value);
1437   };
1438 
1439   StringId cat_id = storage->InternString(base::StringView(kCategory));
1440   add_arg("legacy_event.category", Variadic::String(cat_id));
1441   StringId name_id = storage->InternString(base::StringView(kName));
1442   add_arg("legacy_event.name", Variadic::String(name_id));
1443   StringId phase_id = storage->InternString(base::StringView(kPhase));
1444   add_arg("legacy_event.phase", Variadic::String(phase_id));
1445 
1446   add_arg("legacy_event.duration_ns", Variadic::Integer(kDuration));
1447   add_arg("legacy_event.thread_timestamp_ns",
1448           Variadic::Integer(kThreadTimestamp));
1449   add_arg("legacy_event.thread_duration_ns",
1450           Variadic::Integer(kThreadDuration));
1451   add_arg("legacy_event.thread_instruction_count",
1452           Variadic::Integer(kThreadInstructionCount));
1453   add_arg("legacy_event.thread_instruction_delta",
1454           Variadic::Integer(kThreadInstructionDelta));
1455   add_arg("legacy_event.use_async_tts", Variadic::Boolean(true));
1456   add_arg("legacy_event.global_id", Variadic::UnsignedInteger(kGlobalId));
1457   StringId scope_id = storage->InternString(base::StringView(kIdScope));
1458   add_arg("legacy_event.id_scope", Variadic::String(scope_id));
1459   add_arg("legacy_event.bind_id", Variadic::UnsignedInteger(kBindId));
1460   add_arg("legacy_event.bind_to_enclosing", Variadic::Boolean(true));
1461   StringId flow_direction_id = storage->InternString(kFlowDirection);
1462   add_arg("legacy_event.flow_direction", Variadic::String(flow_direction_id));
1463 
1464   add_arg(kArgName, Variadic::Integer(kArgValue));
1465 
1466   context_.args_tracker->Flush();
1467 
1468   base::TempFile temp_file = base::TempFile::Create();
1469   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1470   base::Status status = ExportJson(storage, output);
1471 
1472   EXPECT_TRUE(status.ok());
1473 
1474   Json::Value result = ToJsonValue(ReadFile(output));
1475   EXPECT_EQ(result["traceEvents"].size(), 1u);
1476 
1477   Json::Value event = result["traceEvents"][0];
1478   EXPECT_EQ(event["ph"].asString(), kPhase);
1479   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
1480   EXPECT_EQ(event["dur"].asInt64(), kDuration / 1000);
1481   EXPECT_EQ(event["tts"].asInt64(), kThreadTimestamp / 1000);
1482   EXPECT_EQ(event["tdur"].asInt64(), kThreadDuration / 1000);
1483   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
1484   EXPECT_EQ(event["tidelta"].asInt64(), kThreadInstructionDelta);
1485   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
1486   EXPECT_EQ(event["cat"].asString(), kCategory);
1487   EXPECT_EQ(event["name"].asString(), kName);
1488   EXPECT_EQ(event["use_async_tts"].asInt(), 1);
1489   EXPECT_EQ(event["id2"]["global"].asString(), "0xaaffaaffaaffaaff");
1490   EXPECT_EQ(event["scope"].asString(), kIdScope);
1491   EXPECT_EQ(event["args"][kArgName].asInt(), kArgValue);
1492 }
1493 
TEST_F(ExportJsonTest,LegacyRawEvents)1494 TEST_F(ExportJsonTest, LegacyRawEvents) {
1495   const char* kLegacyFtraceData = "some \"data\"\nsome :data:";
1496   const char* kLegacyJsonData1 = "{\"us";
1497   const char* kLegacyJsonData2 = "er\": 1},{\"user\": 2}";
1498 
1499   TraceStorage* storage = context_.storage.get();
1500   auto* raw = storage->mutable_raw_table();
1501 
1502   auto id_and_row = raw->Insert(
1503       {0, storage->InternString("chrome_event.legacy_system_trace"), 0, 0});
1504   auto inserter = context_.args_tracker->AddArgsTo(id_and_row.id);
1505 
1506   StringId data_id = storage->InternString("data");
1507   StringId ftrace_data_id = storage->InternString(kLegacyFtraceData);
1508   inserter.AddArg(data_id, Variadic::String(ftrace_data_id));
1509 
1510   id_and_row = raw->Insert(
1511       {0, storage->InternString("chrome_event.legacy_user_trace"), 0, 0});
1512   inserter = context_.args_tracker->AddArgsTo(id_and_row.id);
1513   StringId json_data1_id = storage->InternString(kLegacyJsonData1);
1514   inserter.AddArg(data_id, Variadic::String(json_data1_id));
1515 
1516   id_and_row = raw->Insert(
1517       {0, storage->InternString("chrome_event.legacy_user_trace"), 0, 0});
1518   inserter = context_.args_tracker->AddArgsTo(id_and_row.id);
1519   StringId json_data2_id = storage->InternString(kLegacyJsonData2);
1520   inserter.AddArg(data_id, Variadic::String(json_data2_id));
1521 
1522   context_.args_tracker->Flush();
1523 
1524   base::TempFile temp_file = base::TempFile::Create();
1525   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1526   base::Status status = ExportJson(storage, output);
1527 
1528   EXPECT_TRUE(status.ok());
1529 
1530   Json::Value result = ToJsonValue(ReadFile(output));
1531 
1532   EXPECT_EQ(result["traceEvents"].size(), 2u);
1533   EXPECT_EQ(result["traceEvents"][0]["user"].asInt(), 1);
1534   EXPECT_EQ(result["traceEvents"][1]["user"].asInt(), 2);
1535   EXPECT_EQ(result["systemTraceEvents"].asString(), kLegacyFtraceData);
1536 }
1537 
TEST_F(ExportJsonTest,CpuProfileEvent)1538 TEST_F(ExportJsonTest, CpuProfileEvent) {
1539   const uint32_t kProcessID = 100;
1540   const uint32_t kThreadID = 200;
1541   const int64_t kTimestamp = 10000000;
1542   const int32_t kProcessPriority = 42;
1543 
1544   TraceStorage* storage = context_.storage.get();
1545 
1546   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
1547   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1548 
1549   auto& tt = *context_.storage->mutable_thread_table();
1550   tt[utid].set_upid(upid);
1551 
1552   auto* mappings = storage->mutable_stack_profile_mapping_table();
1553   auto& frames = *storage->mutable_stack_profile_frame_table();
1554   auto* callsites = storage->mutable_stack_profile_callsite_table();
1555 
1556   auto module_1 =
1557       mappings->Insert({storage->InternString("foo_module_id"), 0, 0, 0, 0, 0,
1558                         storage->InternString("foo_module_name")});
1559 
1560   auto module_2 =
1561       mappings->Insert({storage->InternString("bar_module_id"), 0, 0, 0, 0, 0,
1562                         storage->InternString("bar_module_name")});
1563 
1564   // TODO(140860736): Once we support null values for
1565   // stack_profile_frame.symbol_set_id remove this hack
1566   storage->mutable_symbol_table()->Insert({0, kNullStringId, kNullStringId, 0});
1567 
1568   auto frame_1 = frames.Insert({/*in_name=*/kNullStringId, module_1.id, 0x42});
1569 
1570   uint32_t symbol_set_id = storage->symbol_table().row_count();
1571   storage->mutable_symbol_table()->Insert(
1572       {symbol_set_id, storage->InternString("foo_func"),
1573        storage->InternString("foo_file"), 66});
1574   frames[frame_1.row].set_symbol_set_id(symbol_set_id);
1575 
1576   auto frame_2 =
1577       frames.Insert({/*in_name=*/kNullStringId, module_2.id, 0x4242});
1578 
1579   symbol_set_id = storage->symbol_table().row_count();
1580   storage->mutable_symbol_table()->Insert(
1581       {symbol_set_id, storage->InternString("bar_func"),
1582        storage->InternString("bar_file"), 77});
1583   frames[frame_2.row].set_symbol_set_id(symbol_set_id);
1584 
1585   auto frame_callsite_1 = callsites->Insert({0, std::nullopt, frame_1.id});
1586 
1587   auto frame_callsite_2 =
1588       callsites->Insert({1, frame_callsite_1.id, frame_2.id});
1589 
1590   storage->mutable_cpu_profile_stack_sample_table()->Insert(
1591       {kTimestamp, frame_callsite_2.id, utid, kProcessPriority});
1592 
1593   storage->mutable_cpu_profile_stack_sample_table()->Insert(
1594       {kTimestamp + 10000, frame_callsite_1.id, utid, kProcessPriority});
1595 
1596   storage->mutable_cpu_profile_stack_sample_table()->Insert(
1597       {kTimestamp + 20000, frame_callsite_1.id, utid, kProcessPriority});
1598 
1599   base::TempFile temp_file = base::TempFile::Create();
1600   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1601   base::Status status = ExportJson(storage, output);
1602 
1603   EXPECT_TRUE(status.ok());
1604 
1605   Json::Value result = ToJsonValue(ReadFile(output));
1606 
1607   // The first sample should generate only a single instant event;
1608   // the two following samples should also generate an additional [b, e] pair
1609   // (the async duration event).
1610   EXPECT_EQ(result["traceEvents"].size(), 5u);
1611   Json::Value event = result["traceEvents"][0];
1612   EXPECT_EQ(event["ph"].asString(), "n");
1613   EXPECT_EQ(event["id"].asString(), "0x1");
1614   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
1615   EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
1616   EXPECT_EQ(event["cat"].asString(), "disabled-by-default-cpu_profiler");
1617   EXPECT_EQ(event["name"].asString(), "StackCpuSampling");
1618   EXPECT_EQ(event["s"].asString(), "t");
1619   EXPECT_EQ(event["args"]["frames"].asString(),
1620             "foo_func - foo_module_name [foo_module_id]\nbar_func - "
1621             "bar_module_name [bar_module_id]\n");
1622   EXPECT_EQ(event["args"]["process_priority"].asInt(), kProcessPriority);
1623 
1624   event = result["traceEvents"][1];
1625   EXPECT_EQ(event["ph"].asString(), "n");
1626   EXPECT_EQ(event["id"].asString(), "0x2");
1627   EXPECT_EQ(event["ts"].asInt64(), (kTimestamp + 10000) / 1000);
1628 
1629   event = result["traceEvents"][2];
1630   EXPECT_EQ(event["ph"].asString(), "n");
1631   EXPECT_EQ(event["id"].asString(), "0x2");
1632   EXPECT_EQ(event["ts"].asInt64(), (kTimestamp + 20000) / 1000);
1633   Json::String second_callstack_ = event["args"]["frames"].asString();
1634   EXPECT_EQ(second_callstack_, "foo_func - foo_module_name [foo_module_id]\n");
1635 
1636   event = result["traceEvents"][3];
1637   EXPECT_EQ(event["ph"].asString(), "b");
1638   EXPECT_EQ(event["id"].asString(), "0x2");
1639   EXPECT_EQ(event["ts"].asInt64(), (kTimestamp + 10000) / 1000 - 1);
1640   EXPECT_EQ(event["args"]["frames"].asString(), second_callstack_);
1641 
1642   event = result["traceEvents"][4];
1643   EXPECT_EQ(event["ph"].asString(), "e");
1644   EXPECT_EQ(event["id"].asString(), "0x2");
1645   EXPECT_EQ(event["ts"].asInt64(), (kTimestamp + 20000) / 1000);
1646 }
1647 
TEST_F(ExportJsonTest,ArgumentFilter)1648 TEST_F(ExportJsonTest, ArgumentFilter) {
1649   UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
1650   TrackId track = context_.track_tracker->InternThreadTrack(utid);
1651   context_.args_tracker->Flush();  // Flush track args.
1652 
1653   StringId cat_id = context_.storage->InternString(base::StringView("cat"));
1654   std::array<StringId, 3> name_ids{
1655       context_.storage->InternString(base::StringView("name1")),
1656       context_.storage->InternString(base::StringView("name2")),
1657       context_.storage->InternString(base::StringView("name3"))};
1658   StringId arg1_id = context_.storage->InternString(base::StringView("arg1"));
1659   StringId arg2_id = context_.storage->InternString(base::StringView("arg2"));
1660   StringId val_id = context_.storage->InternString(base::StringView("val"));
1661 
1662   auto* slices = context_.storage->mutable_slice_table();
1663   std::vector<ArgsTracker::BoundInserter> slice_inserters;
1664   for (size_t i = 0; i < name_ids.size(); i++) {
1665     auto id = slices->Insert({0, 0, track, cat_id, name_ids[i], 0, 0, 0}).id;
1666     slice_inserters.emplace_back(context_.args_tracker->AddArgsTo(id));
1667   }
1668 
1669   for (auto& inserter : slice_inserters) {
1670     inserter.AddArg(arg1_id, Variadic::Integer(5))
1671         .AddArg(arg2_id, Variadic::String(val_id));
1672   }
1673   context_.args_tracker->Flush();
1674 
1675   auto arg_filter = [](const char* category_group_name, const char* event_name,
1676                        ArgumentNameFilterPredicate* arg_name_filter) {
1677     EXPECT_TRUE(strcmp(category_group_name, "cat") == 0);
1678     if (strcmp(event_name, "name1") == 0) {
1679       // Filter all args for name1.
1680       return false;
1681     }
1682     if (strcmp(event_name, "name2") == 0) {
1683       // Filter only the second arg for name2.
1684       *arg_name_filter = [](const char* arg_name) {
1685         if (strcmp(arg_name, "arg1") == 0) {
1686           return true;
1687         }
1688         EXPECT_TRUE(strcmp(arg_name, "arg2") == 0);
1689         return false;
1690       };
1691       return true;
1692     }
1693     // Filter no args for name3.
1694     EXPECT_TRUE(strcmp(event_name, "name3") == 0);
1695     return true;
1696   };
1697 
1698   Json::Value result = ToJsonValue(ToJson(arg_filter));
1699 
1700   EXPECT_EQ(result["traceEvents"].size(), 3u);
1701 
1702   EXPECT_EQ(result["traceEvents"][0]["cat"].asString(), "cat");
1703   EXPECT_EQ(result["traceEvents"][0]["name"].asString(), "name1");
1704   EXPECT_EQ(result["traceEvents"][0]["args"].asString(), "__stripped__");
1705 
1706   EXPECT_EQ(result["traceEvents"][1]["cat"].asString(), "cat");
1707   EXPECT_EQ(result["traceEvents"][1]["name"].asString(), "name2");
1708   EXPECT_EQ(result["traceEvents"][1]["args"]["arg1"].asInt(), 5);
1709   EXPECT_EQ(result["traceEvents"][1]["args"]["arg2"].asString(),
1710             "__stripped__");
1711 
1712   EXPECT_EQ(result["traceEvents"][2]["cat"].asString(), "cat");
1713   EXPECT_EQ(result["traceEvents"][2]["name"].asString(), "name3");
1714   EXPECT_EQ(result["traceEvents"][2]["args"]["arg1"].asInt(), 5);
1715   EXPECT_EQ(result["traceEvents"][2]["args"]["arg2"].asString(), "val");
1716 }
1717 
TEST_F(ExportJsonTest,MetadataFilter)1718 TEST_F(ExportJsonTest, MetadataFilter) {
1719   const char* kName1 = "name1";
1720   const char* kName2 = "name2";
1721   const char* kValue1 = "value1";
1722   const int kValue2 = 222;
1723 
1724   TraceStorage* storage = context_.storage.get();
1725 
1726   auto* raw = storage->mutable_raw_table();
1727   RawId id =
1728       raw->Insert({0, storage->InternString("chrome_event.metadata"), 0, 0}).id;
1729 
1730   StringId name1_id = storage->InternString(base::StringView(kName1));
1731   StringId name2_id = storage->InternString(base::StringView(kName2));
1732   StringId value1_id = storage->InternString(base::StringView(kValue1));
1733 
1734   context_.args_tracker->AddArgsTo(id)
1735       .AddArg(name1_id, Variadic::String(value1_id))
1736       .AddArg(name2_id, Variadic::Integer(kValue2));
1737   context_.args_tracker->Flush();
1738 
1739   auto metadata_filter = [](const char* metadata_name) {
1740     // Only allow name1.
1741     return strcmp(metadata_name, "name1") == 0;
1742   };
1743 
1744   Json::Value result = ToJsonValue(ToJson(nullptr, metadata_filter));
1745 
1746   EXPECT_TRUE(result.isMember("metadata"));
1747   Json::Value metadata = result["metadata"];
1748 
1749   EXPECT_EQ(metadata[kName1].asString(), kValue1);
1750   EXPECT_EQ(metadata[kName2].asString(), "__stripped__");
1751 }
1752 
TEST_F(ExportJsonTest,LabelFilter)1753 TEST_F(ExportJsonTest, LabelFilter) {
1754   const int64_t kTimestamp1 = 10000000;
1755   const int64_t kTimestamp2 = 20000000;
1756   const int64_t kDuration = 10000;
1757   const uint32_t kThreadID = 100;
1758   const char* kCategory = "cat";
1759   const char* kName = "name";
1760 
1761   UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
1762   TrackId track = context_.track_tracker->InternThreadTrack(utid);
1763   context_.args_tracker->Flush();  // Flush track args.
1764   StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
1765   StringId name_id = context_.storage->InternString(base::StringView(kName));
1766 
1767   context_.storage->mutable_slice_table()->Insert(
1768       {kTimestamp1, kDuration, track, cat_id, name_id, 0, 0, 0});
1769   context_.storage->mutable_slice_table()->Insert(
1770       {kTimestamp2, kDuration, track, cat_id, name_id, 0, 0, 0});
1771 
1772   auto label_filter = [](const char* label_name) {
1773     return strcmp(label_name, "traceEvents") == 0;
1774   };
1775 
1776   Json::Value result =
1777       ToJsonValue("[" + ToJson(nullptr, nullptr, label_filter) + "]");
1778 
1779   EXPECT_TRUE(result.isArray());
1780   EXPECT_EQ(result.size(), 2u);
1781 
1782   EXPECT_EQ(result[0]["ph"].asString(), "X");
1783   EXPECT_EQ(result[0]["ts"].asInt64(), kTimestamp1 / 1000);
1784   EXPECT_EQ(result[0]["dur"].asInt64(), kDuration / 1000);
1785   EXPECT_EQ(result[0]["tid"].asInt(), static_cast<int>(kThreadID));
1786   EXPECT_EQ(result[0]["cat"].asString(), kCategory);
1787   EXPECT_EQ(result[0]["name"].asString(), kName);
1788   EXPECT_EQ(result[1]["ph"].asString(), "X");
1789   EXPECT_EQ(result[1]["ts"].asInt64(), kTimestamp2 / 1000);
1790   EXPECT_EQ(result[1]["dur"].asInt64(), kDuration / 1000);
1791   EXPECT_EQ(result[1]["tid"].asInt(), static_cast<int>(kThreadID));
1792   EXPECT_EQ(result[1]["cat"].asString(), kCategory);
1793   EXPECT_EQ(result[1]["name"].asString(), kName);
1794 }
1795 
TEST_F(ExportJsonTest,MemorySnapshotOsDumpEvent)1796 TEST_F(ExportJsonTest, MemorySnapshotOsDumpEvent) {
1797   const int64_t kTimestamp = 10000000;
1798   const int64_t kPeakResidentSetSize = 100000;
1799   const int64_t kPrivateFootprintBytes = 200000;
1800   const int64_t kProtectionFlags = 1;
1801   const int64_t kStartAddress = 1000000000;
1802   const int64_t kSizeKb = 1000;
1803   const int64_t kPrivateCleanResidentKb = 2000;
1804   const int64_t kPrivateDirtyKb = 3000;
1805   const int64_t kProportionalResidentKb = 4000;
1806   const int64_t kSharedCleanResidentKb = 5000;
1807   const int64_t kSharedDirtyResidentKb = 6000;
1808   const int64_t kSwapKb = 7000;
1809   const int64_t kModuleTimestamp = 20000000;
1810   const uint32_t kProcessID = 100;
1811   const bool kIsPeakRssResettable = true;
1812   const char* kLevelOfDetail = "detailed";
1813   const char* kFileName = "filename";
1814   const char* kModuleDebugid = "debugid";
1815   const char* kModuleDebugPath = "debugpath";
1816 
1817   UniquePid upid = context_.process_tracker->GetOrCreateProcess(kProcessID);
1818   TrackId track =
1819       context_.track_tracker->InternProcessTrack(tracks::track_event, upid);
1820   StringId level_of_detail_id =
1821       context_.storage->InternString(base::StringView(kLevelOfDetail));
1822   auto snapshot_id = context_.storage->mutable_memory_snapshot_table()
1823                          ->Insert({kTimestamp, track, level_of_detail_id})
1824                          .id;
1825 
1826   TrackId peak_resident_set_size_counter = context_.track_tracker->InternTrack(
1827       tracks::kChromeProcessStatsBlueprint,
1828       tracks::Dimensions(upid, "peak_resident_set_kb"));
1829   context_.event_tracker->PushCounter(kTimestamp, kPeakResidentSetSize,
1830                                       peak_resident_set_size_counter);
1831 
1832   TrackId private_footprint_bytes_counter = context_.track_tracker->InternTrack(
1833       tracks::kChromeProcessStatsBlueprint,
1834       tracks::Dimensions(upid, "private_footprint_kb"));
1835   context_.event_tracker->PushCounter(kTimestamp, kPrivateFootprintBytes,
1836                                       private_footprint_bytes_counter);
1837 
1838   StringId is_peak_rss_resettable_id =
1839       context_.storage->InternString("is_peak_rss_resettable");
1840   context_.args_tracker->AddArgsTo(upid).AddArg(
1841       is_peak_rss_resettable_id, Variadic::Boolean(kIsPeakRssResettable));
1842   context_.args_tracker->Flush();
1843 
1844   context_.storage->mutable_profiler_smaps_table()->Insert(
1845       {upid, kTimestamp, kNullStringId, kSizeKb, kPrivateDirtyKb, kSwapKb,
1846        context_.storage->InternString(kFileName), kStartAddress,
1847        kModuleTimestamp, context_.storage->InternString(kModuleDebugid),
1848        context_.storage->InternString(kModuleDebugPath), kProtectionFlags,
1849        kPrivateCleanResidentKb, kSharedDirtyResidentKb, kSharedCleanResidentKb,
1850        0, kProportionalResidentKb});
1851 
1852   base::TempFile temp_file = base::TempFile::Create();
1853   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1854   base::Status status = ExportJson(context_.storage.get(), output);
1855 
1856   EXPECT_TRUE(status.ok());
1857 
1858   Json::Value result = ToJsonValue(ReadFile(output));
1859   EXPECT_EQ(result["traceEvents"].size(), 1u);
1860 
1861   Json::Value event = result["traceEvents"][0];
1862   EXPECT_EQ(event["ph"].asString(), "v");
1863   EXPECT_EQ(event["cat"].asString(), "disabled-by-default-memory-infra");
1864   EXPECT_EQ(event["id"].asString(), base::Uint64ToHexString(snapshot_id.value));
1865   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
1866   EXPECT_EQ(event["name"].asString(), "periodic_interval");
1867   EXPECT_EQ(event["pid"].asUInt(), kProcessID);
1868   EXPECT_EQ(event["tid"].asInt(), -1);
1869 
1870   EXPECT_TRUE(event["args"].isObject());
1871   EXPECT_EQ(event["args"]["dumps"]["level_of_detail"].asString(),
1872             kLevelOfDetail);
1873 
1874   EXPECT_EQ(event["args"]["dumps"]["process_totals"]["peak_resident_set_size"]
1875                 .asString(),
1876             base::Uint64ToHexStringNoPrefix(
1877                 static_cast<uint64_t>(kPeakResidentSetSize)));
1878   EXPECT_EQ(event["args"]["dumps"]["process_totals"]["private_footprint_bytes"]
1879                 .asString(),
1880             base::Uint64ToHexStringNoPrefix(
1881                 static_cast<uint64_t>(kPrivateFootprintBytes)));
1882   EXPECT_EQ(event["args"]["dumps"]["process_totals"]["is_peak_rss_resettable"]
1883                 .asBool(),
1884             kIsPeakRssResettable);
1885 
1886   EXPECT_TRUE(event["args"]["dumps"]["process_mmaps"]["vm_regions"].isArray());
1887   EXPECT_EQ(event["args"]["dumps"]["process_mmaps"]["vm_regions"].size(), 1u);
1888   Json::Value region = event["args"]["dumps"]["process_mmaps"]["vm_regions"][0];
1889   EXPECT_EQ(region["mf"].asString(), kFileName);
1890   EXPECT_EQ(region["pf"].asInt64(), kProtectionFlags);
1891   EXPECT_EQ(region["sa"].asString(), base::Uint64ToHexStringNoPrefix(
1892                                          static_cast<uint64_t>(kStartAddress)));
1893   EXPECT_EQ(
1894       region["sz"].asString(),
1895       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(kSizeKb * 1024)));
1896   EXPECT_EQ(region["id"].asString(), kModuleDebugid);
1897   EXPECT_EQ(region["df"].asString(), kModuleDebugPath);
1898   EXPECT_EQ(region["bs"]["pc"].asString(),
1899             base::Uint64ToHexStringNoPrefix(
1900                 static_cast<uint64_t>(kPrivateCleanResidentKb * 1024)));
1901   EXPECT_EQ(region["bs"]["pd"].asString(),
1902             base::Uint64ToHexStringNoPrefix(
1903                 static_cast<uint64_t>(kPrivateDirtyKb * 1024)));
1904   EXPECT_EQ(region["bs"]["pss"].asString(),
1905             base::Uint64ToHexStringNoPrefix(
1906                 static_cast<uint64_t>(kProportionalResidentKb * 1024)));
1907   EXPECT_EQ(region["bs"]["sc"].asString(),
1908             base::Uint64ToHexStringNoPrefix(
1909                 static_cast<uint64_t>(kSharedCleanResidentKb * 1024)));
1910   EXPECT_EQ(region["bs"]["sd"].asString(),
1911             base::Uint64ToHexStringNoPrefix(
1912                 static_cast<uint64_t>(kSharedDirtyResidentKb * 1024)));
1913   EXPECT_EQ(
1914       region["bs"]["sw"].asString(),
1915       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(kSwapKb * 1024)));
1916 }
1917 
TEST_F(ExportJsonTest,MemorySnapshotChromeDumpEvent)1918 TEST_F(ExportJsonTest, MemorySnapshotChromeDumpEvent) {
1919   const int64_t kTimestamp = 10000000;
1920   const int64_t kSize = 1000;
1921   const int64_t kEffectiveSize = 2000;
1922   const int64_t kScalarAttrValue = 3000;
1923   const uint32_t kOsProcessID = 100;
1924   const uint32_t kChromeProcessID = 200;
1925   const uint32_t kImportance = 1;
1926   const char* kLevelOfDetail = "detailed";
1927   const char* kPath1 = "path/to_file1";
1928   const char* kPath2 = "path/to_file2";
1929   const char* kScalarAttrUnits = "scalar_units";
1930   const char* kStringAttrValue = "string_value";
1931   const std::string kScalarAttrName = "scalar_name";
1932   const std::string kStringAttrName = "string_name";
1933 
1934   UniquePid os_upid =
1935       context_.process_tracker->GetOrCreateProcess(kOsProcessID);
1936   TrackId track =
1937       context_.track_tracker->InternProcessTrack(tracks::track_event, os_upid);
1938   StringId level_of_detail_id =
1939       context_.storage->InternString(base::StringView(kLevelOfDetail));
1940   auto snapshot_id = context_.storage->mutable_memory_snapshot_table()
1941                          ->Insert({kTimestamp, track, level_of_detail_id})
1942                          .id;
1943 
1944   UniquePid chrome_upid =
1945       context_.process_tracker->GetOrCreateProcess(kChromeProcessID);
1946   auto process_id = context_.storage->mutable_process_memory_snapshot_table()
1947                         ->Insert({snapshot_id, chrome_upid})
1948                         .id;
1949 
1950   StringId path1_id = context_.storage->InternString(base::StringView(kPath1));
1951   StringId path2_id = context_.storage->InternString(base::StringView(kPath2));
1952   SnapshotNodeId node1_id =
1953       context_.storage->mutable_memory_snapshot_node_table()
1954           ->Insert(
1955               {process_id, SnapshotNodeId(0), path1_id, kSize, kEffectiveSize})
1956           .id;
1957   SnapshotNodeId node2_id =
1958       context_.storage->mutable_memory_snapshot_node_table()
1959           ->Insert({process_id, SnapshotNodeId(0), path2_id, 0, 0})
1960           .id;
1961 
1962   context_.args_tracker->AddArgsTo(node1_id).AddArg(
1963       context_.storage->InternString(
1964           base::StringView(kScalarAttrName + ".value")),
1965       Variadic::Integer(kScalarAttrValue));
1966   context_.args_tracker->AddArgsTo(node1_id).AddArg(
1967       context_.storage->InternString(
1968           base::StringView(kScalarAttrName + ".unit")),
1969       Variadic::String(context_.storage->InternString(kScalarAttrUnits)));
1970   context_.args_tracker->AddArgsTo(node1_id).AddArg(
1971       context_.storage->InternString(
1972           base::StringView(kStringAttrName + ".value")),
1973       Variadic::String(context_.storage->InternString(kStringAttrValue)));
1974   context_.args_tracker->Flush();
1975 
1976   context_.storage->mutable_memory_snapshot_edge_table()->Insert(
1977       {node1_id, node2_id, kImportance});
1978 
1979   base::TempFile temp_file = base::TempFile::Create();
1980   FILE* output = fopen(temp_file.path().c_str(), "w+e");
1981   base::Status status = ExportJson(context_.storage.get(), output);
1982 
1983   EXPECT_TRUE(status.ok());
1984 
1985   Json::Value result = ToJsonValue(ReadFile(output));
1986   EXPECT_EQ(result["traceEvents"].size(), 1u);
1987 
1988   Json::Value event = result["traceEvents"][0];
1989   EXPECT_EQ(event["ph"].asString(), "v");
1990   EXPECT_EQ(event["cat"].asString(), "disabled-by-default-memory-infra");
1991   EXPECT_EQ(event["id"].asString(), base::Uint64ToHexString(snapshot_id.value));
1992   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
1993   EXPECT_EQ(event["name"].asString(), "periodic_interval");
1994   EXPECT_EQ(event["pid"].asUInt(), kChromeProcessID);
1995   EXPECT_EQ(event["tid"].asInt(), -1);
1996 
1997   EXPECT_TRUE(event["args"].isObject());
1998   EXPECT_EQ(event["args"]["dumps"]["level_of_detail"].asString(),
1999             kLevelOfDetail);
2000 
2001   EXPECT_EQ(event["args"]["dumps"]["allocators"].size(), 2u);
2002   Json::Value node1 = event["args"]["dumps"]["allocators"][kPath1];
2003   EXPECT_TRUE(node1.isObject());
2004   EXPECT_EQ(
2005       node1["guid"].asString(),
2006       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(node1_id.value)));
2007   EXPECT_TRUE(node1["attrs"]["size"].isObject());
2008   EXPECT_EQ(node1["attrs"]["size"]["value"].asString(),
2009             base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(kSize)));
2010   EXPECT_EQ(node1["attrs"]["size"]["type"].asString(), "scalar");
2011   EXPECT_EQ(node1["attrs"]["size"]["units"].asString(), "bytes");
2012   EXPECT_EQ(
2013       node1["attrs"]["effective_size"]["value"].asString(),
2014       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(kEffectiveSize)));
2015   EXPECT_TRUE(node1["attrs"][kScalarAttrName].isObject());
2016   EXPECT_EQ(
2017       node1["attrs"][kScalarAttrName]["value"].asString(),
2018       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(kScalarAttrValue)));
2019   EXPECT_EQ(node1["attrs"][kScalarAttrName]["type"].asString(), "scalar");
2020   EXPECT_EQ(node1["attrs"][kScalarAttrName]["units"].asString(),
2021             kScalarAttrUnits);
2022   EXPECT_TRUE(node1["attrs"][kStringAttrName].isObject());
2023   EXPECT_EQ(node1["attrs"][kStringAttrName]["value"].asString(),
2024             kStringAttrValue);
2025   EXPECT_EQ(node1["attrs"][kStringAttrName]["type"].asString(), "string");
2026   EXPECT_EQ(node1["attrs"][kStringAttrName]["units"].asString(), "");
2027 
2028   Json::Value node2 = event["args"]["dumps"]["allocators"][kPath2];
2029   EXPECT_TRUE(node2.isObject());
2030   EXPECT_EQ(
2031       node2["guid"].asString(),
2032       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(node2_id.value)));
2033   EXPECT_TRUE(node2["attrs"].empty());
2034 
2035   Json::Value graph = event["args"]["dumps"]["allocators_graph"];
2036   EXPECT_TRUE(graph.isArray());
2037   EXPECT_EQ(graph.size(), 1u);
2038   EXPECT_EQ(
2039       graph[0]["source"].asString(),
2040       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(node1_id.value)));
2041   EXPECT_EQ(
2042       graph[0]["target"].asString(),
2043       base::Uint64ToHexStringNoPrefix(static_cast<uint64_t>(node2_id.value)));
2044   EXPECT_EQ(graph[0]["importance"].asUInt(), kImportance);
2045   EXPECT_EQ(graph[0]["type"].asString(), "ownership");
2046 }
2047 
2048 }  // namespace
2049 }  // namespace perfetto::trace_processor::json
2050