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