| /* |
| * 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 |