blob: 74a69cccce133922dec76447cb5f2142ecaa6e4b [file] [log] [blame]
/*
* Copyright (C) 2021 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 "odr_metrics_record.h"
#include <iosfwd>
#include <string>
#include "android-base/logging.h"
#include "tinyxml2.h"
namespace art {
namespace odrefresh {
namespace {
android::base::Result<int64_t> ReadInt64(tinyxml2::XMLElement* parent, const char* name) {
tinyxml2::XMLElement* element = parent->FirstChildElement(name);
if (element == nullptr) {
return Errorf("Expected Odrefresh metric {} not found", name);
}
int64_t metric;
tinyxml2::XMLError result = element->QueryInt64Text(&metric);
if (result == tinyxml2::XML_SUCCESS) {
return metric;
} else {
return Errorf("Odrefresh metric {} is not an int64", name);
}
}
android::base::Result<int32_t> ReadInt32(tinyxml2::XMLElement* parent, const char* name) {
tinyxml2::XMLElement* element = parent->FirstChildElement(name);
if (element == nullptr) {
return Errorf("Expected Odrefresh metric {} not found", name);
}
int32_t metric;
tinyxml2::XMLError result = element->QueryIntText(&metric);
if (result == tinyxml2::XML_SUCCESS) {
return metric;
} else {
return Errorf("Odrefresh metric {} is not an int32", name);
}
}
android::base::Result<int32_t> ReadInt32Attribute(tinyxml2::XMLElement* element,
const char* element_name,
const char* attribute_name,
int min_value,
int max_value) {
int32_t value;
tinyxml2::XMLError result = element->QueryAttribute(attribute_name, &value);
if (result != tinyxml2::XML_SUCCESS) {
return Errorf("Expected Odrefresh metric {}.{} is not an int32", element_name, attribute_name);
}
if (value < min_value || value > max_value) {
return Errorf(
"Odrefresh metric {}.{} has a value ({}) outside of the expected range ([{}, {}])",
element_name,
attribute_name,
value,
min_value,
max_value);
}
return value;
}
android::base::Result<OdrMetricsRecord::Dex2OatExecResult> ReadExecResult(
tinyxml2::XMLElement* parent, const char* nodeName) {
tinyxml2::XMLElement* element = parent->FirstChildElement(nodeName);
if (element == nullptr) {
return Errorf("Expected Odrefresh metric {} not found", nodeName);
}
return OdrMetricsRecord::Dex2OatExecResult(
OR_RETURN(ReadInt32Attribute(element, nodeName, "status", 0, kExecResultNotRun)),
OR_RETURN(ReadInt32Attribute(element, nodeName, "exit-code", -1, 255)),
OR_RETURN(ReadInt32Attribute(element, nodeName, "signal", 0, SIGRTMAX)));
}
template <typename T>
void AddMetric(tinyxml2::XMLElement* parent, const char* name, const T& value) {
parent->InsertNewChildElement(name)->SetText(value);
}
void AddResult(tinyxml2::XMLElement* parent,
const char* name,
const OdrMetricsRecord::Dex2OatExecResult& execResult) {
tinyxml2::XMLElement* result = parent->InsertNewChildElement(name);
result->SetAttribute("status", execResult.status);
result->SetAttribute("exit-code", execResult.exit_code);
result->SetAttribute("signal", execResult.signal);
}
} // namespace
android::base::Result<void> OdrMetricsRecord::ReadFromFile(const std::string& filename) {
tinyxml2::XMLDocument xml_document;
tinyxml2::XMLError result = xml_document.LoadFile(filename.data());
if (result != tinyxml2::XML_SUCCESS) {
return android::base::Error() << xml_document.ErrorStr();
}
tinyxml2::XMLElement* metrics = xml_document.FirstChildElement("odrefresh_metrics");
if (metrics == nullptr) {
return Errorf("odrefresh_metrics element not found in {}", filename);
}
odrefresh_metrics_version = OR_RETURN(ReadInt32(metrics, "odrefresh_metrics_version"));
if (odrefresh_metrics_version != kOdrefreshMetricsVersion) {
return Errorf("odrefresh_metrics_version {} is different than expected ({})",
odrefresh_metrics_version,
kOdrefreshMetricsVersion);
}
art_apex_version = OR_RETURN(ReadInt64(metrics, "art_apex_version"));
trigger = OR_RETURN(ReadInt32(metrics, "trigger"));
stage_reached = OR_RETURN(ReadInt32(metrics, "stage_reached"));
status = OR_RETURN(ReadInt32(metrics, "status"));
cache_space_free_start_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_start_mib"));
cache_space_free_end_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_end_mib"));
primary_bcp_compilation_millis = OR_RETURN(ReadInt32(metrics, "primary_bcp_compilation_millis"));
secondary_bcp_compilation_millis =
OR_RETURN(ReadInt32(metrics, "secondary_bcp_compilation_millis"));
system_server_compilation_millis =
OR_RETURN(ReadInt32(metrics, "system_server_compilation_millis"));
primary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "primary_bcp_dex2oat_result"));
secondary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "secondary_bcp_dex2oat_result"));
system_server_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "system_server_dex2oat_result"));
primary_bcp_compilation_type = OR_RETURN(ReadInt32(metrics, "primary_bcp_compilation_type"));
secondary_bcp_compilation_type = OR_RETURN(ReadInt32(metrics, "secondary_bcp_compilation_type"));
return {};
}
android::base::Result<void> OdrMetricsRecord::WriteToFile(const std::string& filename) const {
tinyxml2::XMLDocument xml_document;
tinyxml2::XMLElement* metrics = xml_document.NewElement("odrefresh_metrics");
xml_document.InsertEndChild(metrics);
// The order here matches the field order of MetricsRecord.
AddMetric(metrics, "odrefresh_metrics_version", odrefresh_metrics_version);
AddMetric(metrics, "art_apex_version", art_apex_version);
AddMetric(metrics, "trigger", trigger);
AddMetric(metrics, "stage_reached", stage_reached);
AddMetric(metrics, "status", status);
AddMetric(metrics, "cache_space_free_start_mib", cache_space_free_start_mib);
AddMetric(metrics, "cache_space_free_end_mib", cache_space_free_end_mib);
AddMetric(metrics, "primary_bcp_compilation_millis", primary_bcp_compilation_millis);
AddMetric(metrics, "secondary_bcp_compilation_millis", secondary_bcp_compilation_millis);
AddMetric(metrics, "system_server_compilation_millis", system_server_compilation_millis);
AddResult(metrics, "primary_bcp_dex2oat_result", primary_bcp_dex2oat_result);
AddResult(metrics, "secondary_bcp_dex2oat_result", secondary_bcp_dex2oat_result);
AddResult(metrics, "system_server_dex2oat_result", system_server_dex2oat_result);
AddMetric(metrics, "primary_bcp_compilation_type", primary_bcp_compilation_type);
AddMetric(metrics, "secondary_bcp_compilation_type", secondary_bcp_compilation_type);
tinyxml2::XMLError result = xml_document.SaveFile(filename.data(), /*compact=*/true);
if (result == tinyxml2::XML_SUCCESS) {
return {};
} else {
return android::base::Error() << xml_document.ErrorStr();
}
}
} // namespace odrefresh
} // namespace art