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