1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "odr_metrics_record.h"
18
19 #include <iosfwd>
20 #include <string>
21
22 #include "android-base/logging.h"
23 #include "tinyxml2.h"
24
25 namespace art {
26 namespace odrefresh {
27
28 namespace {
ReadInt64(tinyxml2::XMLElement * parent,const char * name)29 android::base::Result<int64_t> ReadInt64(tinyxml2::XMLElement* parent, const char* name) {
30 tinyxml2::XMLElement* element = parent->FirstChildElement(name);
31 if (element == nullptr) {
32 return Errorf("Expected Odrefresh metric {} not found", name);
33 }
34
35 int64_t metric;
36 tinyxml2::XMLError result = element->QueryInt64Text(&metric);
37 if (result == tinyxml2::XML_SUCCESS) {
38 return metric;
39 } else {
40 return Errorf("Odrefresh metric {} is not an int64", name);
41 }
42 }
43
ReadInt32(tinyxml2::XMLElement * parent,const char * name)44 android::base::Result<int32_t> ReadInt32(tinyxml2::XMLElement* parent, const char* name) {
45 tinyxml2::XMLElement* element = parent->FirstChildElement(name);
46 if (element == nullptr) {
47 return Errorf("Expected Odrefresh metric {} not found", name);
48 }
49
50 int32_t metric;
51 tinyxml2::XMLError result = element->QueryIntText(&metric);
52 if (result == tinyxml2::XML_SUCCESS) {
53 return metric;
54 } else {
55 return Errorf("Odrefresh metric {} is not an int32", name);
56 }
57 }
58
ReadInt32Attribute(tinyxml2::XMLElement * element,const char * element_name,const char * attribute_name,int min_value,int max_value)59 android::base::Result<int32_t> ReadInt32Attribute(tinyxml2::XMLElement* element,
60 const char* element_name,
61 const char* attribute_name,
62 int min_value,
63 int max_value) {
64 int32_t value;
65 tinyxml2::XMLError result = element->QueryAttribute(attribute_name, &value);
66 if (result != tinyxml2::XML_SUCCESS) {
67 return Errorf("Expected Odrefresh metric {}.{} is not an int32", element_name, attribute_name);
68 }
69
70 if (value < min_value || value > max_value) {
71 return Errorf(
72 "Odrefresh metric {}.{} has a value ({}) outside of the expected range ([{}, {}])",
73 element_name,
74 attribute_name,
75 value,
76 min_value,
77 max_value);
78 }
79
80 return value;
81 }
82
ReadExecResult(tinyxml2::XMLElement * parent,const char * nodeName)83 android::base::Result<OdrMetricsRecord::Dex2OatExecResult> ReadExecResult(
84 tinyxml2::XMLElement* parent, const char* nodeName) {
85 tinyxml2::XMLElement* element = parent->FirstChildElement(nodeName);
86 if (element == nullptr) {
87 return Errorf("Expected Odrefresh metric {} not found", nodeName);
88 }
89
90 return OdrMetricsRecord::Dex2OatExecResult(
91 OR_RETURN(ReadInt32Attribute(element, nodeName, "status", 0, kExecResultNotRun)),
92 OR_RETURN(ReadInt32Attribute(element, nodeName, "exit-code", -1, 255)),
93 OR_RETURN(ReadInt32Attribute(element, nodeName, "signal", 0, SIGRTMAX)));
94 }
95
96 template <typename T>
AddMetric(tinyxml2::XMLElement * parent,const char * name,const T & value)97 void AddMetric(tinyxml2::XMLElement* parent, const char* name, const T& value) {
98 parent->InsertNewChildElement(name)->SetText(value);
99 }
100
AddResult(tinyxml2::XMLElement * parent,const char * name,const OdrMetricsRecord::Dex2OatExecResult & execResult)101 void AddResult(tinyxml2::XMLElement* parent,
102 const char* name,
103 const OdrMetricsRecord::Dex2OatExecResult& execResult) {
104 tinyxml2::XMLElement* result = parent->InsertNewChildElement(name);
105 result->SetAttribute("status", execResult.status);
106 result->SetAttribute("exit-code", execResult.exit_code);
107 result->SetAttribute("signal", execResult.signal);
108 }
109 } // namespace
110
ReadFromFile(const std::string & filename)111 android::base::Result<void> OdrMetricsRecord::ReadFromFile(const std::string& filename) {
112 tinyxml2::XMLDocument xml_document;
113 tinyxml2::XMLError result = xml_document.LoadFile(filename.data());
114 if (result != tinyxml2::XML_SUCCESS) {
115 return android::base::Error() << xml_document.ErrorStr();
116 }
117
118 tinyxml2::XMLElement* metrics = xml_document.FirstChildElement("odrefresh_metrics");
119 if (metrics == nullptr) {
120 return Errorf("odrefresh_metrics element not found in {}", filename);
121 }
122
123 odrefresh_metrics_version = OR_RETURN(ReadInt32(metrics, "odrefresh_metrics_version"));
124 if (odrefresh_metrics_version != kOdrefreshMetricsVersion) {
125 return Errorf("odrefresh_metrics_version {} is different than expected ({})",
126 odrefresh_metrics_version,
127 kOdrefreshMetricsVersion);
128 }
129
130 art_apex_version = OR_RETURN(ReadInt64(metrics, "art_apex_version"));
131 trigger = OR_RETURN(ReadInt32(metrics, "trigger"));
132 stage_reached = OR_RETURN(ReadInt32(metrics, "stage_reached"));
133 status = OR_RETURN(ReadInt32(metrics, "status"));
134 cache_space_free_start_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_start_mib"));
135 cache_space_free_end_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_end_mib"));
136 primary_bcp_compilation_millis = OR_RETURN(ReadInt32(metrics, "primary_bcp_compilation_millis"));
137 secondary_bcp_compilation_millis =
138 OR_RETURN(ReadInt32(metrics, "secondary_bcp_compilation_millis"));
139 system_server_compilation_millis =
140 OR_RETURN(ReadInt32(metrics, "system_server_compilation_millis"));
141 primary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "primary_bcp_dex2oat_result"));
142 secondary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "secondary_bcp_dex2oat_result"));
143 system_server_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "system_server_dex2oat_result"));
144 primary_bcp_compilation_type = OR_RETURN(ReadInt32(metrics, "primary_bcp_compilation_type"));
145 secondary_bcp_compilation_type = OR_RETURN(ReadInt32(metrics, "secondary_bcp_compilation_type"));
146
147 return {};
148 }
149
WriteToFile(const std::string & filename) const150 android::base::Result<void> OdrMetricsRecord::WriteToFile(const std::string& filename) const {
151 tinyxml2::XMLDocument xml_document;
152 tinyxml2::XMLElement* metrics = xml_document.NewElement("odrefresh_metrics");
153 xml_document.InsertEndChild(metrics);
154
155 // The order here matches the field order of MetricsRecord.
156 AddMetric(metrics, "odrefresh_metrics_version", odrefresh_metrics_version);
157 AddMetric(metrics, "art_apex_version", art_apex_version);
158 AddMetric(metrics, "trigger", trigger);
159 AddMetric(metrics, "stage_reached", stage_reached);
160 AddMetric(metrics, "status", status);
161 AddMetric(metrics, "cache_space_free_start_mib", cache_space_free_start_mib);
162 AddMetric(metrics, "cache_space_free_end_mib", cache_space_free_end_mib);
163 AddMetric(metrics, "primary_bcp_compilation_millis", primary_bcp_compilation_millis);
164 AddMetric(metrics, "secondary_bcp_compilation_millis", secondary_bcp_compilation_millis);
165 AddMetric(metrics, "system_server_compilation_millis", system_server_compilation_millis);
166 AddResult(metrics, "primary_bcp_dex2oat_result", primary_bcp_dex2oat_result);
167 AddResult(metrics, "secondary_bcp_dex2oat_result", secondary_bcp_dex2oat_result);
168 AddResult(metrics, "system_server_dex2oat_result", system_server_dex2oat_result);
169 AddMetric(metrics, "primary_bcp_compilation_type", primary_bcp_compilation_type);
170 AddMetric(metrics, "secondary_bcp_compilation_type", secondary_bcp_compilation_type);
171
172 tinyxml2::XMLError result = xml_document.SaveFile(filename.data(), /*compact=*/true);
173 if (result == tinyxml2::XML_SUCCESS) {
174 return {};
175 } else {
176 return android::base::Error() << xml_document.ErrorStr();
177 }
178 }
179
180 } // namespace odrefresh
181 } // namespace art
182