• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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