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