182 lines
7.4 KiB
C++
182 lines
7.4 KiB
C++
/*
|
|
* 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
|