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