blob: bb2a604056bff1ae6f2fb93b81df5af7afd2a574 [file]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <chrono>
#include "common/gamesdk_common.h"
#include "core/tuningfork_utils.h"
#include "http_backend/json_serializer.h"
#include "test_utils.h"
namespace serialization_test {
using namespace tuningfork;
using namespace gamesdk_test;
using namespace json11;
using namespace std::chrono;
RequestInfo test_device_info{
"expt" /*experiment_id*/,
{} /*current_fidelity_parameters*/,
"sess" /*session_id*/,
"prev_sess" /*previous_session_id*/,
2387 /*total_memory_bytes*/,
349587 /*gl_es_version*/,
"fing" /*build_fingerprint*/,
"6.3" /*build_version_sdk*/,
{1, 2, 3} /*cpu_max_freq_hz*/,
"packname" /*apk_package_name*/,
0 /*apk_version_code*/,
ANDROID_GAMESDK_PACKED_VERSION(0, 10, 0) /*tuningfork_version*/,
"MODEL" /*model*/,
"BRAND" /*brand*/,
"PRODUCT" /*product*/,
"DEVICE" /*device*/,
"SOC_MODEL" /*soc_model*/,
"SOC_MANUFACTURER" /*soc_manufacturer*/,
234 /*swap_total_bytes*/,
ANDROID_GAMESDK_PACKED_VERSION(2, 7, 0) /*swappy_version*/,
1024 /*height_pixels*/,
768 /*width_pixels*/};
std::string test_device_info_ser = R"TF({
"brand": "BRAND",
"build_version": "6.3",
"cpu_core_freqs_hz": [1, 2, 3],
"device": "DEVICE",
"fingerprint": "fing",
"gles_version": {
"major": 5, "minor": 21907
},
"height_pixels": 1024,
"model": "MODEL",
"product": "PRODUCT",
"soc_manufacturer": "SOC_MANUFACTURER",
"soc_model": "SOC_MODEL",
"swap_total_bytes": 234,
"total_memory_bytes": 2387,
"width_pixels": 768
})TF";
void CheckDeviceInfo(const RequestInfo& info) {
EXPECT_EQ(json_utils::GetResourceName(info), "applications/packname/apks/0")
<< "GetResourceName";
EXPECT_TRUE(CompareIgnoringWhitespace(
Json(json_utils::DeviceSpecJson(info)).dump(), test_device_info_ser))
<< "DeviceSpecJson";
}
TEST(SerializationTest, DeviceInfo) { CheckDeviceInfo(test_device_info); }
std::string report_start = R"TF({
"name": "applications/packname/apks/0",
"session_context": {
"device": {
"brand": "BRAND",
"build_version": "6.3",
"cpu_core_freqs_hz": [1, 2, 3],
"device": "DEVICE",
"fingerprint": "fing",
"gles_version": {
"major": 5,
"minor": 21907
},
"height_pixels": 1024,
"model": "MODEL",
"product": "PRODUCT",
"soc_manufacturer": "SOC_MANUFACTURER",
"soc_model": "SOC_MODEL",
"swap_total_bytes": 234,
"total_memory_bytes": 2387,
"width_pixels": 768
},
"game_sdk_info": {
"session_id": "sess",
"swappy_version": "2.7.0",
"version": "0.10.0"
},
"time_period": {
"end_time": "1970-01-01T00:00:00.000000Z",
"start_time": "1970-01-01T00:00:00.000000Z"
}
},
"telemetry": [)TF";
std::string report_end = "]}";
std::string single_tick_with_loading = R"TF({
"context": {
"annotations": "AQID",
"duration": "1.5s",
"tuning_parameters": {
"experiment_id": "expt",
"serialized_fidelity_parameters": ""
}
},
"report": {
"loading": {
"loading_events": [{
"loading_metadata": {
"group_id": "ABC",
"network_info": {
"bandwidth_bps": "1000000000",
"connectivity": 1,
"latency": "0.05s"
},
"source":5,
"state":1
},
"times_ms": [1500]
}]
},
"rendering": {
"render_time_histogram": [{"counts": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"instrument_id": 1234
}]
}
}
})TF";
class IdMap : public IdProvider {
TuningFork_ErrorCode SerializedAnnotationToAnnotationId(
const ProtobufSerialization& ser, AnnotationId& id) override {
id = 0;
return TUNINGFORK_ERROR_OK;
}
// Return a new id that is made up of <annotation_id> and <k>.
// Gives an error if the id is out-of-bounds.
TuningFork_ErrorCode MakeCompoundId(InstrumentationKey k,
AnnotationId annotation_id,
MetricId& id) override {
id = MetricId::FrameTime(annotation_id, k);
return TUNINGFORK_ERROR_OK;
}
TuningFork_ErrorCode AnnotationIdToSerializedAnnotation(
AnnotationId id, SerializedAnnotation& ann) override {
ann = {1, 2, 3};
return TUNINGFORK_ERROR_OK;
}
TuningFork_ErrorCode MetricIdToLoadingTimeMetadata(
MetricId id, LoadingTimeMetadataWithGroup& mg) override {
LoadingTimeMetadata& m = mg.metadata;
m = {};
m.state = LoadingTimeMetadata::FIRST_RUN;
m.source = LoadingTimeMetadata::NETWORK;
m.network_latency_ns = 50000000; // 50ms
m.network_connectivity = LoadingTimeMetadata::NetworkConnectivity::WIFI;
m.network_transfer_speed_bps = 1000000000; // 1Gb/s
mg.group_id = "ABC";
return TUNINGFORK_ERROR_OK;
}
};
TEST(SerializationTest, SerializationWithLoading) {
Session session{};
MetricId loading_time_metric = MetricId::LoadingTime(0, 0);
MetricId frame_time_metric = MetricId::FrameTime(0, 0);
session.CreateLoadingTimeSeries(loading_time_metric);
session.CreateFrameTimeHistogram(frame_time_metric,
Settings::DefaultHistogram(1));
std::string evt_ser;
session.SetInstrumentationKeys({1234});
IdMap metric_map;
JsonSerializer serializer(session, &metric_map);
serializer.SerializeEvent(test_device_info, evt_ser);
auto empty_report = report_start + report_end;
EXPECT_TRUE(CompareIgnoringWhitespace(evt_ser, empty_report))
<< evt_ser << "\n!=\n"
<< empty_report;
// Fill in some data
auto p1 = session.GetData<LoadingTimeMetricData>(loading_time_metric);
ASSERT_NE(p1, nullptr);
p1->Record(milliseconds(1500));
auto p2 = session.GetData<FrameTimeMetricData>(frame_time_metric);
ASSERT_NE(p2, nullptr);
p2->Record(milliseconds(10));
// Try to record with some LoadingTimeMetadata - this will fail because we
// didn't allocate any extra loading time space.
MetricId new_loading_time_metric = MetricId::LoadingTime(0, 1);
EXPECT_EQ(session.GetData<LoadingTimeMetricData>(new_loading_time_metric),
nullptr);
serializer.SerializeEvent(test_device_info, evt_ser);
auto report = report_start + single_tick_with_loading + report_end;
EXPECT_TRUE(CompareIgnoringWhitespace(evt_ser, report))
<< evt_ser << "\n!=\n"
<< report;
}
std::string single_tick = R"TF({
"context": {
"annotations": "AQID",
"duration": "0.03s",
"tuning_parameters": {
"experiment_id": "expt",
"serialized_fidelity_parameters": ""
}
},
"report": {
"rendering": {
"render_time_histogram": [{
"counts": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"instrument_id": 0
}]
}
}
})TF";
void CheckSessions(Session& pc0, Session& pc1) {
auto p0 = pc0.GetData<FrameTimeMetricData>(MetricId::FrameTime(0, 0));
auto p1 = pc1.GetData<FrameTimeMetricData>(MetricId::FrameTime(0, 0));
EXPECT_TRUE(p0 != nullptr && p1 != nullptr);
EXPECT_EQ(p0->histogram_, p1->histogram_);
}
Settings::Histogram DefaultHistogram() { return {-1, 10, 40, 30}; }
TEST(SerializationTest, GEDeserialization) {
Session session{};
FrameTimeMetric metric(0);
MetricId metric_id{0};
session.CreateFrameTimeHistogram(metric_id, DefaultHistogram());
std::string evt_ser;
IdMap metric_map;
JsonSerializer serializer(session, &metric_map);
serializer.SerializeEvent(test_device_info, evt_ser);
auto empty_report = report_start + report_end;
EXPECT_TRUE(CompareIgnoringWhitespace(evt_ser, empty_report))
<< evt_ser << "\n!=\n"
<< empty_report;
// Fill in some data
auto p = session.GetData<FrameTimeMetricData>(metric_id);
p->Record(milliseconds(30));
serializer.SerializeEvent(test_device_info, evt_ser);
auto report = report_start + single_tick + report_end;
EXPECT_TRUE(CompareIgnoringWhitespace(evt_ser, report))
<< evt_ser << "\n!=\n"
<< report;
Session session1{};
session1.CreateFrameTimeHistogram(metric_id, DefaultHistogram());
EXPECT_EQ(
JsonSerializer::DeserializeAndMerge(evt_ser, metric_map, session1),
TUNINGFORK_ERROR_OK)
<< "Deserialize single";
CheckSessions(session1, session);
}
TEST(SerializationTest, DurationSerialization) {
std::vector<double> ds = {1e19, 1e15, 1e10, 1e5, 1e0, 1e-1,
1e-3, 1e-5, 1e-8, 1e-9, 1e-10, 1e-15};
std::vector<std::string> results = {"10000000000000000000",
"1000000000000000",
"10000000000",
"100000",
"1",
"0.1",
"0.001",
"0.00001",
"0.00000001",
"0.000000001",
"0",
"0"};
EXPECT_EQ(ds.size(), results.size()) << "Test set up badly";
for (int i = 0; i < std::min(ds.size(), results.size()); ++i) {
std::stringstream str;
str << JsonSerializer::FixedAndTruncated(ds[i]);
EXPECT_EQ(str.str(), results[i])
<< "expected " << results[i] << " got " << str.str();
}
}
} // namespace serialization_test