blob: 88bc4c7bb5df2f8d18f3f93a9529bf8869495367 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/arc/tracing/arc_tracing_model.h"
#include <set>
#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/trace_event/common/trace_event_common.h"
#include "chrome/browser/ash/arc/tracing/arc_tracing_event.h"
#include "chrome/browser/ash/arc/tracing/arc_tracing_event_matcher.h"
#include "chrome/browser/ash/arc/tracing/arc_tracing_graphics_model.h"
#include "chrome/browser/ash/arc/tracing/present_frames_tracer.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/compression_utils.h"
namespace arc {
namespace {
using GraphicsEvents = ArcTracingGraphicsModel::BufferEvents;
using GraphicsEventType = ArcTracingGraphicsModel::EventType;
constexpr char kAcquireBufferQuery[] =
"android:onMessageReceived/android:handleMessageInvalidate/"
"android:latchBuffer/android:updateTexImage/android:acquireBuffer";
constexpr char kAttachSurfaceQueury[] =
"toplevel:OnLibevent/exo:Surface::Attach";
constexpr char kTestEvent[] =
R"({"pid":4640,"tid":4641,"id":"1234","ts":14241877057,"ph":"X","cat":"exo",
"name":"Surface::Attach",
"args":{"buffer_id":"0x7f9f5110690","app_id":"org.chromium.arc.6"},
"dur":10,"tdur":9,"tts":1216670360})";
constexpr char kTestEvent2[] =
R"({"args":{},"cat":"exo","id2":{"local":"0x2df1a3130a10"},
"name":"BufferInUse","ph":"F","pid":17518,"tid":17518,
"ts":7654346859.0,"tts":93686437})";
constexpr char kAppId[] = "app_id";
constexpr char kAppIdValue[] = "org.chromium.arc.6";
constexpr char kBufferId[] = "buffer_id";
constexpr char kBufferIdBad[] = "_buffer_id";
constexpr char kBufferIdValue[] = "0x7f9f5110690";
constexpr char kBufferIdValueBad[] = "_0x7f9f5110690";
constexpr char kBufferInUse[] = "BufferInUse";
constexpr char kDefault[] = "default";
constexpr char kExo[] = "exo";
constexpr char kExoBad[] = "_exo";
constexpr char kPhaseF = 'F';
constexpr char kPhaseP = 'P';
constexpr char kPhaseX = 'X';
constexpr char kSurfaceAttach[] = "Surface::Attach";
constexpr char kSurfaceAttachBad[] = "_Surface::Attach";
// Validates that events have increasing timestamp, and all events have allowed
// transitions from the previous state.
bool ValidateCpuEvents(const CpuEvents& cpu_events) {
if (cpu_events.empty()) {
return false;
}
CpuEvents cpu_events_reconstructed;
for (const auto& cpu_event : cpu_events) {
if (!AddCpuEvent(&cpu_events_reconstructed, cpu_event.timestamp,
cpu_event.type, cpu_event.tid)) {
return false;
}
}
return cpu_events_reconstructed == cpu_events;
}
// Validates that events have increasing timestamp, have only allowed types and
// each type is found at least once.
bool ValidateGrahpicsEvents(const GraphicsEvents& events,
const std::set<GraphicsEventType>& allowed_types) {
bool ok = true;
uint64_t previous_timestamp = 0;
std::set<GraphicsEventType> used_types;
for (const auto& event : events) {
if (event.timestamp < previous_timestamp) {
LOG(ERROR) << "Timestamp sequence broken: " << event.timestamp << " vs "
<< previous_timestamp << ".";
ok = false;
}
previous_timestamp = event.timestamp;
if (!allowed_types.count(event.type)) {
LOG(ERROR) << "Unexpected event type " << event.type << ".";
ok = false;
}
used_types.insert(event.type);
}
for (const auto& allowed_type : allowed_types) {
if (!used_types.count(allowed_type)) {
LOG(ERROR) << "Required event type " << allowed_type
<< " << is not found.";
ok = false;
}
}
return ok;
}
std::unique_ptr<ArcTracingGraphicsModel> LoadGraphicsModel(
const std::string& name) {
base::FilePath base_path;
base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
const base::FilePath tracing_path =
base_path.Append("arc_overview_tracing").Append(name);
std::string json_data;
base::ReadFileToString(tracing_path, &json_data);
DCHECK(!json_data.empty());
std::unique_ptr<ArcTracingGraphicsModel> model =
std::make_unique<ArcTracingGraphicsModel>();
if (!model->LoadFromJson(json_data)) {
return nullptr;
}
return model;
}
// Ensures |model1| is equal to |model2|.
void EnsureGraphicsModelsEqual(const ArcTracingGraphicsModel& model1,
const ArcTracingGraphicsModel& model2) {
EXPECT_EQ(model1.chrome_top_level(), model2.chrome_top_level());
EXPECT_EQ(model1.view_buffers(), model2.view_buffers());
EXPECT_EQ(model1.system_model(), model2.system_model());
EXPECT_EQ(model1.duration(), model2.duration());
EXPECT_EQ(model1.app_title(), model2.app_title());
EXPECT_EQ(model1.app_icon_png(), model2.app_icon_png());
EXPECT_EQ(model1.timestamp(), model2.timestamp());
EXPECT_EQ(model1.platform(), model2.platform());
}
} // namespace
class ArcTracingModelTest : public testing::Test {
public:
ArcTracingModelTest() = default;
ArcTracingModelTest(const ArcTracingModelTest&) = delete;
ArcTracingModelTest& operator=(const ArcTracingModelTest&) = delete;
~ArcTracingModelTest() override = default;
};
// TopLevel test is performed on the data collected from the real test device.
// It tests that model can be built from the provided data and queries work.
TEST_F(ArcTracingModelTest, TopLevel) {
base::FilePath base_path;
base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
const base::FilePath tracing_path =
base_path.Append("arc_overview_tracing").Append("trace.dat.gz");
std::string tracing_data_compressed;
ASSERT_TRUE(base::ReadFileToString(tracing_path, &tracing_data_compressed));
std::string tracing_data;
ASSERT_TRUE(
compression::GzipUncompress(tracing_data_compressed, &tracing_data));
ArcTracingModel model;
ASSERT_TRUE(model.Build(tracing_data));
// 4 CPU cores.
EXPECT_EQ(4U, model.system_model().all_cpu_events().size());
for (const auto& cpu_events : model.system_model().all_cpu_events()) {
EXPECT_TRUE(ValidateCpuEvents(cpu_events));
}
// Perform several well-known queries.
EXPECT_FALSE(model.Select(kAcquireBufferQuery).empty());
EXPECT_FALSE(model.Select(kAttachSurfaceQueury).empty());
std::stringstream ss;
model.Dump(ss);
EXPECT_FALSE(ss.str().empty());
// Continue in this test to avoid heavy calculations for building base model.
// Make sure we can create graphics model.
ArcTracingGraphicsModel graphics_model;
PresentFramesTracer present_frames;
present_frames.AddCommit(base::TimeTicks::FromUptimeMillis(42));
ASSERT_TRUE(graphics_model.Build(model, present_frames));
EXPECT_EQ(1U, graphics_model.chrome_top_level().buffer_events().size());
for (const auto& chrome_top_level_band :
graphics_model.chrome_top_level().buffer_events()) {
EXPECT_TRUE(ValidateGrahpicsEvents(chrome_top_level_band, {}));
}
EXPECT_FALSE(graphics_model.view_buffers().empty());
for (const auto& view : graphics_model.view_buffers()) {
// At least one buffer.
EXPECT_GT(view.first.task_id, 0);
EXPECT_NE(std::string(), view.first.activity);
EXPECT_FALSE(view.second.buffer_events().empty());
for (const auto& buffer : view.second.buffer_events()) {
EXPECT_TRUE(ValidateGrahpicsEvents(
buffer, {GraphicsEventType::kExoSurfaceCommit}));
}
}
// Note, CPU events in |graphics_model| are normalized by timestamp. So they
// are not equal and we cannot do direct comparison. Also first VSYNC event
// trimming may drop some events.
ASSERT_LE(graphics_model.system_model().all_cpu_events().size(),
model.system_model().all_cpu_events().size());
EXPECT_EQ(graphics_model.system_model().thread_map(),
model.system_model().thread_map());
for (size_t i = 0; i < graphics_model.system_model().all_cpu_events().size();
++i) {
EXPECT_LE(graphics_model.system_model().all_cpu_events()[i].size(),
model.system_model().all_cpu_events()[i].size());
}
EXPECT_GT(graphics_model.duration(), 0U);
// Serialize and restore;
const std::string graphics_model_data = graphics_model.SerializeToJson();
EXPECT_FALSE(graphics_model_data.empty());
ArcTracingGraphicsModel graphics_model_loaded;
EXPECT_TRUE(graphics_model_loaded.LoadFromJson(graphics_model_data));
// Models should match.
EnsureGraphicsModelsEqual(graphics_model, graphics_model_loaded);
}
TEST_F(ArcTracingModelTest, FrameDisplayed) {
std::string tracing_data = R"({"traceEvents":[
{"args":{},"cat":"benchmark,viz,disabled-by-default-display.framedisplayed","name":"Display::FrameDisplayed","ph":"I","pid":18869,"s":"t","tid":18912,"ts":4966534893},
{"args":{},"cat":"benchmark,viz,disabled-by-default-display.framedisplayed","name":"Display::FrameDisplayed","ph":"I","pid":18869,"s":"t","tid":18912,"ts":4966551562},
{"args":{},"cat":"benchmark,viz,disabled-by-default-display.framedisplayed","name":"Display::FrameDisplayed","ph":"I","pid":18869,"s":"t","tid":18912,"ts":4966568229}
],"systemTraceEvents":""})";
ArcTracingModel model;
ASSERT_TRUE(model.Build(tracing_data));
ArcTracingGraphicsModel graphics_model;
ASSERT_TRUE(graphics_model.Build(model, {}));
EXPECT_TRUE(ValidateGrahpicsEvents(
graphics_model.chrome_top_level().buffer_events()[0],
{GraphicsEventType::kChromeOSSwapDone}));
}
// Validates basic system event timestamp processing
TEST_F(ArcTracingModelTest, SystemTraceEventTimestampParsing) {
{
std::string tracing_data =
"{\"traceEvents\":[],\"systemTraceEvents\":\""
// clang-format off
" surfaceflinger-9772 [000] ...0 80156.539255: tracing_mark_write: B|15|acquireBuffer\n"
// clang-format on
"\"}";
ArcTracingModel model;
ASSERT_TRUE(model.Build(tracing_data));
const ArcTracingModel::TracingEventPtrs events =
model.Select("android:acquireBuffer");
ASSERT_EQ(1u, events.size());
EXPECT_EQ(15, events[0]->GetPid());
EXPECT_EQ("android", events[0]->GetCategory());
EXPECT_EQ("acquireBuffer", events[0]->GetName());
EXPECT_EQ('X', events[0]->GetPhase());
EXPECT_EQ(80156539255UL, events[0]->GetTimestamp());
EXPECT_EQ(0U, events[0]->GetDuration());
}
{
// Too few digits after the timestamp decimal point should be an error
std::string bad_tracing_data_1 =
"{\"traceEvents\":[],\"systemTraceEvents\":\""
// clang-format off
" surfaceflinger-9772 [000] ...0 999.12345: tracing_mark_write: B|15|acquireBuffer\n"
// clang-format on
"\"}";
ArcTracingModel model;
EXPECT_FALSE(model.Build(bad_tracing_data_1));
}
{
// Too many digits after the timestamp decimal point should be an error
std::string bad_tracing_data_2 =
"{\"traceEvents\":[],\"systemTraceEvents\":\""
// clang-format off
" surfaceflinger-9772 [000] ...0 999.1234567: tracing_mark_write: B|15|acquireBuffer\n"
// clang-format on
"\"}";
ArcTracingModel model;
EXPECT_FALSE(model.Build(bad_tracing_data_2));
}
}
namespace {
bool TestSystemTraceEventExtraFlags(const char* flag_field) {
std::string tracing_data =
base::StrCat({"{\"traceEvents\":[],\"systemTraceEvents\":\""
// clang-format off
" surfaceflinger-9772 [000] ", flag_field, " 987.123456: tracing_mark_write: B|51|acquireBuffer\n"
// clang-format on
"\"}"});
ArcTracingModel model;
if (!model.Build(tracing_data)) {
return false;
}
const ArcTracingModel::TracingEventPtrs events =
model.Select("android:acquireBuffer");
CHECK_EQ(1u, events.size());
EXPECT_EQ(51, events[0]->GetPid());
EXPECT_EQ("android", events[0]->GetCategory());
EXPECT_EQ("acquireBuffer", events[0]->GetName());
EXPECT_EQ('X', events[0]->GetPhase());
EXPECT_EQ(987123456UL, events[0]->GetTimestamp());
EXPECT_EQ(0U, events[0]->GetDuration());
return true;
}
} // namespace
TEST_F(ArcTracingModelTest, SystemTraceEventMoreFlags) {
// Kernel v5.15 has 5 flags after the CPU#, whereas v5.10 has only 4. Verify
// we don't fail for 5 flags, or more in case future kernels get them.
// Empty flags field - two spaces between CPU# and timestamp fields.
EXPECT_FALSE(TestSystemTraceEventExtraFlags(""));
EXPECT_FALSE(TestSystemTraceEventExtraFlags("0"));
EXPECT_FALSE(TestSystemTraceEventExtraFlags(".0"));
EXPECT_FALSE(TestSystemTraceEventExtraFlags("..0"));
EXPECT_TRUE(TestSystemTraceEventExtraFlags("...0"));
EXPECT_TRUE(TestSystemTraceEventExtraFlags("....0"));
EXPECT_TRUE(TestSystemTraceEventExtraFlags(".....0"));
EXPECT_TRUE(TestSystemTraceEventExtraFlags("......0"));
}
TEST_F(ArcTracingModelTest, SystemTraceEventCpuEventProcessing) {
std::string tracing_data =
"{\"traceEvents\":[],\"systemTraceEvents\":\""
// clang-format off
" <idle>-0 [000] d..0 123.000001: cpu_idle: state=0 cpu_id=0\n"
" <idle>-0 [000] dn.0 123.000002: cpu_idle: state=4294967295 cpu_id=0\n"
" <idle>-0 [000] dnh3 123.000003: sched_wakeup: comm=foo pid=15821 prio=115 target_cpu=000\n"
" <idle>-0 [000] d..3 123.000004: sched_switch: prev_comm=bar prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=baz next_pid=15821 next_prio=115\n"
// clang-format on
"\"}";
ArcTracingModel model;
ASSERT_TRUE(model.Build(tracing_data));
const AllCpuEvents& cpu_events = model.system_model().all_cpu_events();
ASSERT_EQ(1u, cpu_events.size());
CpuEvents cpu0_events = cpu_events[0];
ASSERT_EQ(4u, cpu0_events.size());
EXPECT_EQ(123000001UL, cpu0_events[0].timestamp);
EXPECT_EQ(ArcCpuEvent::Type::kIdleIn, cpu0_events[0].type);
EXPECT_EQ(0u, cpu0_events[0].tid);
EXPECT_EQ(123000002UL, cpu0_events[1].timestamp);
EXPECT_EQ(ArcCpuEvent::Type::kIdleOut, cpu0_events[1].type);
EXPECT_EQ(0u, cpu0_events[1].tid);
EXPECT_EQ(123000003UL, cpu0_events[2].timestamp);
EXPECT_EQ(ArcCpuEvent::Type::kWakeUp, cpu0_events[2].type);
EXPECT_EQ(15821u, cpu0_events[2].tid);
EXPECT_EQ(123000004UL, cpu0_events[3].timestamp);
EXPECT_EQ(ArcCpuEvent::Type::kActive, cpu0_events[3].type);
EXPECT_EQ(15821u, cpu0_events[3].tid);
}
TEST_F(ArcTracingModelTest, Event) {
const ArcTracingEvent event(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
EXPECT_EQ(4640, event.GetPid());
EXPECT_EQ(4641, event.GetTid());
EXPECT_EQ("1234", event.GetId());
EXPECT_EQ(kExo, event.GetCategory());
EXPECT_EQ(kSurfaceAttach, event.GetName());
EXPECT_EQ(kPhaseX, event.GetPhase());
EXPECT_EQ(14241877057UL, event.GetTimestamp());
EXPECT_EQ(10U, event.GetDuration());
EXPECT_EQ(14241877067UL, event.GetEndTimestamp());
EXPECT_NE(nullptr, event.GetDictionary());
EXPECT_EQ(kBufferIdValue, event.GetArgAsString(kBufferId, std::string()));
EXPECT_EQ(kDefault, event.GetArgAsString(kBufferIdBad, kDefault));
}
TEST_F(ArcTracingModelTest, EventId2) {
const ArcTracingEvent event(std::move(
base::JSONReader::Read(kTestEvent2, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
EXPECT_EQ(17518, event.GetPid());
EXPECT_EQ(17518, event.GetTid());
EXPECT_EQ("0x2df1a3130a10", event.GetId());
EXPECT_EQ(kExo, event.GetCategory());
EXPECT_EQ(kBufferInUse, event.GetName());
EXPECT_EQ(kPhaseF, event.GetPhase());
EXPECT_EQ(7654346859UL, event.GetTimestamp());
EXPECT_EQ(0U, event.GetDuration());
EXPECT_EQ(7654346859UL, event.GetEndTimestamp());
EXPECT_NE(nullptr, event.GetDictionary());
}
TEST_F(ArcTracingModelTest, EventClassification) {
const ArcTracingEvent event(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
ArcTracingEvent event_before(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event_before.SetTimestamp(event.GetTimestamp() - event.GetDuration());
EXPECT_EQ(ArcTracingEvent::Position::kBefore,
event.ClassifyPositionOf(event_before));
ArcTracingEvent event_after(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event_after.SetTimestamp(event.GetTimestamp() + event.GetDuration());
EXPECT_EQ(ArcTracingEvent::Position::kAfter,
event.ClassifyPositionOf(event_after));
ArcTracingEvent event_inside(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event_inside.SetTimestamp(event.GetTimestamp() + 1);
event_inside.SetDuration(event.GetDuration() - 2);
EXPECT_EQ(ArcTracingEvent::Position::kInside,
event.ClassifyPositionOf(event_inside));
EXPECT_EQ(ArcTracingEvent::Position::kInside,
event.ClassifyPositionOf(event));
ArcTracingEvent event_overlap(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event_overlap.SetTimestamp(event.GetTimestamp() + 1);
EXPECT_EQ(ArcTracingEvent::Position::kOverlap,
event.ClassifyPositionOf(event_overlap));
event_overlap.SetTimestamp(event.GetTimestamp());
event_overlap.SetDuration(event.GetDuration() + 1);
EXPECT_EQ(ArcTracingEvent::Position::kOverlap,
event.ClassifyPositionOf(event_overlap));
event_overlap.SetTimestamp(event.GetTimestamp() - 1);
event_overlap.SetDuration(event.GetDuration() + 2);
EXPECT_EQ(ArcTracingEvent::Position::kOverlap,
event.ClassifyPositionOf(event_overlap));
}
TEST_F(ArcTracingModelTest, EventAppendChild) {
ArcTracingEvent event(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
// Impossible to append the even that is bigger than target.
std::unique_ptr<ArcTracingEvent> event_overlap =
std::make_unique<ArcTracingEvent>(
std::move(base::JSONReader::Read(kTestEvent,
base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event_overlap->SetTimestamp(event.GetTimestamp() + 1);
EXPECT_FALSE(event.AppendChild(std::move(event_overlap)));
std::unique_ptr<ArcTracingEvent> event1 = std::make_unique<ArcTracingEvent>(
std::move(base::JSONReader::Read(kTestEvent,
base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event1->SetTimestamp(event.GetTimestamp() + 4);
event1->SetDuration(2);
EXPECT_TRUE(event.AppendChild(std::move(event1)));
EXPECT_EQ(1U, event.children().size());
// Impossible to append the event that is before last child.
std::unique_ptr<ArcTracingEvent> event2 = std::make_unique<ArcTracingEvent>(
std::move(base::JSONReader::Read(kTestEvent,
base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event2->SetTimestamp(event.GetTimestamp());
event2->SetDuration(2);
EXPECT_FALSE(event.AppendChild(std::move(event2)));
EXPECT_EQ(1U, event.children().size());
// Append child to child
std::unique_ptr<ArcTracingEvent> event3 = std::make_unique<ArcTracingEvent>(
std::move(base::JSONReader::Read(kTestEvent,
base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event3->SetTimestamp(event.GetTimestamp() + 5);
event3->SetDuration(1);
EXPECT_TRUE(event.AppendChild(std::move(event3)));
ASSERT_EQ(1U, event.children().size());
EXPECT_EQ(1U, event.children()[0].get()->children().size());
// Append next immediate child.
std::unique_ptr<ArcTracingEvent> event4 = std::make_unique<ArcTracingEvent>(
std::move(base::JSONReader::Read(kTestEvent,
base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
event4->SetTimestamp(event.GetTimestamp() + 6);
event4->SetDuration(2);
EXPECT_TRUE(event.AppendChild(std::move(event4)));
EXPECT_EQ(2U, event.children().size());
}
TEST_F(ArcTracingModelTest, EventMatcher) {
const ArcTracingEvent event(std::move(
base::JSONReader::Read(kTestEvent, base::JSON_PARSE_CHROMIUM_EXTENSIONS)
->GetDict()));
// Nothing is specified. It matches any event.
EXPECT_TRUE(ArcTracingEventMatcher().Match(event));
// Phase
EXPECT_TRUE(ArcTracingEventMatcher().SetPhase(kPhaseX).Match(event));
EXPECT_FALSE(ArcTracingEventMatcher().SetPhase(kPhaseP).Match(event));
// Category
EXPECT_TRUE(ArcTracingEventMatcher().SetCategory(kExo).Match(event));
EXPECT_FALSE(ArcTracingEventMatcher().SetCategory(kExoBad).Match(event));
// Name
EXPECT_TRUE(ArcTracingEventMatcher().SetName(kSurfaceAttach).Match(event));
EXPECT_FALSE(
ArcTracingEventMatcher().SetName(kSurfaceAttachBad).Match(event));
// Arguments
EXPECT_TRUE(ArcTracingEventMatcher()
.AddArgument(kBufferId, kBufferIdValue)
.Match(event));
EXPECT_TRUE(ArcTracingEventMatcher()
.AddArgument(kBufferId, kBufferIdValue)
.AddArgument(kAppId, kAppIdValue)
.Match(event));
EXPECT_FALSE(ArcTracingEventMatcher()
.AddArgument(kBufferIdBad, kBufferIdValue)
.Match(event));
EXPECT_FALSE(ArcTracingEventMatcher()
.AddArgument(kBufferId, kBufferIdValueBad)
.Match(event));
// String query
EXPECT_TRUE(
ArcTracingEventMatcher("exo:Surface::Attach(buffer_id=0x7f9f5110690)")
.Match(event));
EXPECT_FALSE(
ArcTracingEventMatcher("_exo:_Surface::Attach(buffer_id=_0x7f9f5110690)")
.Match(event));
}
TEST_F(ArcTracingModelTest, TimeMinMax) {
// Model contains events with timestamps 100000..100004 inclusively.
base::FilePath base_path;
base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
const base::FilePath tracing_path =
base_path.Append("arc_overview_tracing").Append("trace_time.dat");
std::string tracing_data;
ASSERT_TRUE(base::ReadFileToString(tracing_path, &tracing_data));
ArcTracingModel model_without_time_filter;
EXPECT_TRUE(model_without_time_filter.Build(tracing_data));
EXPECT_EQ(5U, model_without_time_filter.GetRoots().size());
ArcTracingModel model_with_time_filter;
model_with_time_filter.SetMinMaxTime(100001L, 100003L);
EXPECT_TRUE(model_with_time_filter.Build(tracing_data));
ASSERT_EQ(2U, model_with_time_filter.GetRoots().size());
EXPECT_EQ(100001UL, model_with_time_filter.GetRoots()[0]->GetTimestamp());
EXPECT_EQ(100002UL, model_with_time_filter.GetRoots()[1]->GetTimestamp());
ArcTracingModel model_with_empty_time_filter;
model_with_empty_time_filter.SetMinMaxTime(99999L, 100000L);
EXPECT_TRUE(model_with_empty_time_filter.Build(tracing_data));
EXPECT_EQ(0U, model_with_empty_time_filter.GetRoots().size());
}
TEST_F(ArcTracingModelTest, GraphicsModelLoadSerialize) {
std::unique_ptr<ArcTracingGraphicsModel> model =
LoadGraphicsModel("gm_good.json");
ASSERT_TRUE(model);
EXPECT_EQ("CrOS 12642.0.0 (Official Build) dev-channel eve",
model->platform());
EXPECT_EQ("Play Store", model->app_title());
EXPECT_FALSE(model->app_icon_png().empty());
EXPECT_EQ(base::Time::FromMillisecondsSinceUnixEpoch(1572898642036L),
model->timestamp());
EXPECT_EQ(1000U, model->duration());
ArcTracingGraphicsModel test_model;
EXPECT_TRUE(test_model.LoadFromJson(model->SerializeToJson()));
EnsureGraphicsModelsEqual(*model, test_model);
EXPECT_TRUE(LoadGraphicsModel("gm_good.json"));
EXPECT_FALSE(LoadGraphicsModel("gm_bad_no_view_buffers.json"));
EXPECT_FALSE(LoadGraphicsModel("gm_bad_no_view_desc.json"));
EXPECT_FALSE(LoadGraphicsModel("gm_bad_wrong_timestamp.json"));
}
TEST_F(ArcTracingModelTest, AsynchronousSystemEvents) {
base::FilePath base_path;
base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
const base::FilePath tracing_path = base_path.Append("arc_overview_tracing")
.Append("trace_async_events.json");
std::string tracing_data;
base::ReadFileToString(tracing_path, &tracing_data);
DCHECK(!tracing_data.empty());
ArcTracingModel model;
ASSERT_TRUE(model.Build(tracing_data));
const ArcTracingModel::TracingEventPtrs group1 = model.GetGroupEvents("1");
const ArcTracingModel::TracingEventPtrs group2 = model.GetGroupEvents("2");
constexpr char kAsync1[] = "async1";
constexpr char kAsync2[] = "async2";
ASSERT_EQ(2U, group1.size());
EXPECT_EQ(kAsync1, group1[0]->GetName());
EXPECT_EQ(kAsync1, group1[1]->GetName());
EXPECT_EQ("1", group1[0]->GetId());
EXPECT_EQ(group1[0]->GetId(), group1[1]->GetId());
EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, group1[0]->GetPhase());
EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END, group1[1]->GetPhase());
EXPECT_EQ(1100000UL, group1[0]->GetTimestamp());
EXPECT_EQ(1300000UL, group1[1]->GetTimestamp());
ASSERT_EQ(2U, group2.size());
EXPECT_EQ(kAsync2, group2[0]->GetName());
EXPECT_EQ(kAsync2, group2[1]->GetName());
EXPECT_EQ("2", group2[0]->GetId());
EXPECT_EQ(group2[0]->GetId(), group2[1]->GetId());
EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, group2[0]->GetPhase());
EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END, group2[1]->GetPhase());
EXPECT_EQ(1200000UL, group2[0]->GetTimestamp());
EXPECT_EQ(1400000UL, group2[1]->GetTimestamp());
}
} // namespace arc