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 #ifndef ART_ODREFRESH_ODR_METRICS_H_
18 #define ART_ODREFRESH_ODR_METRICS_H_
19 
20 #include <chrono>
21 #include <cstdint>
22 #include <iosfwd>
23 #include <optional>
24 #include <string>
25 
26 #include "base/macros.h"
27 #include "odr_metrics_record.h"
28 
29 namespace art {
30 namespace odrefresh {
31 
32 class OdrMetrics final {
33  public:
34   // Enumeration used to track the latest stage reached running odrefresh.
35   //
36   // These values mirror those in OdrefreshReported::Stage in frameworks/proto_logging/atoms.proto.
37   // NB There are gaps between the values in case an additional stages are introduced.
38   enum class Stage : uint8_t {
39     kUnknown = 0,
40     kCheck = 10,
41     kPreparation = 20,
42     kPrimaryBootClasspath = 30,
43     kSecondaryBootClasspath = 40,
44     kSystemServerClasspath = 50,
45     kComplete = 60,
46   };
47 
48   // Enumeration describing the overall status, processing stops on the first error discovered.
49   //
50   // These values mirror those in OdrefreshReported::Status in frameworks/proto_logging/atoms.proto.
51   enum class Status : uint8_t {
52     kUnknown = 0,
53     kOK = 1,
54     kNoSpace = 2,
55     kIoError = 3,
56     kDex2OatError = 4,
57     kTimeLimitExceeded = 5,
58     kStagingFailed = 6,
59     kInstallFailed = 7,
60   };
61 
62   // Enumeration describing the cause of compilation (if any) in odrefresh.
63   //
64   // These values mirror those in OdrefreshReported::Trigger in
65   // frameworks/proto_logging/atoms.proto.
66   enum class Trigger : uint8_t {
67     kUnknown = 0,
68     kApexVersionMismatch = 1,
69     kDexFilesChanged = 2,
70     kMissingArtifacts = 3,
71   };
72 
73   explicit OdrMetrics(const std::string& cache_directory,
74                       const std::string& metrics_file = kOdrefreshMetricsFile);
75   ~OdrMetrics();
76 
77   // Gets the ART APEX that metrics are being collected on behalf of.
GetArtApexVersion()78   int64_t GetArtApexVersion() const {
79     return art_apex_version_;
80   }
81 
82   // Sets the ART APEX that metrics are being collected on behalf of.
SetArtApexVersion(int64_t version)83   void SetArtApexVersion(int64_t version) {
84     art_apex_version_ = version;
85   }
86 
87   // Gets the ART APEX last update time in milliseconds.
GetArtApexLastUpdateMillis()88   int64_t GetArtApexLastUpdateMillis() const {
89     return art_apex_last_update_millis_;
90   }
91 
92   // Sets the ART APEX last update time in milliseconds.
SetArtApexLastUpdateMillis(int64_t last_update_millis)93   void SetArtApexLastUpdateMillis(int64_t last_update_millis) {
94     art_apex_last_update_millis_ = last_update_millis;
95   }
96 
97   // Gets the trigger for metrics collection. The trigger is the reason why odrefresh considers
98   // compilation necessary.
GetTrigger()99   Trigger GetTrigger() const {
100     return trigger_.has_value() ? trigger_.value() : Trigger::kUnknown;
101   }
102 
103   // Sets the trigger for metrics collection. The trigger is the reason why odrefresh considers
104   // compilation necessary. Only call this method if compilation is necessary as the presence
105   // of a trigger means we will try to record and upload metrics.
SetTrigger(const Trigger trigger)106   void SetTrigger(const Trigger trigger) {
107     trigger_ = trigger;
108   }
109 
110   // Sets the execution status of the current odrefresh processing stage.
SetStatus(const Status status)111   void SetStatus(const Status status) {
112     status_ = status;
113   }
114 
115   // Sets the current odrefresh processing stage.
116   void SetStage(Stage stage);
117 
118   // Record metrics into an OdrMetricsRecord.
119   // returns true on success, false if instance is not valid (because the trigger value is not set).
120   bool ToRecord(/*out*/OdrMetricsRecord* record) const;
121 
122  private:
123   OdrMetrics(const OdrMetrics&) = delete;
124   OdrMetrics operator=(const OdrMetrics&) = delete;
125 
126   static int32_t GetFreeSpaceMiB(const std::string& path);
127   static void WriteToFile(const std::string& path, const OdrMetrics* metrics);
128 
129   void SetCompilationTime(int32_t seconds);
130 
131   const std::string cache_directory_;
132   const std::string metrics_file_;
133 
134   int64_t art_apex_version_ = 0;
135   int64_t art_apex_last_update_millis_ = 0;
136   std::optional<Trigger> trigger_ = {};  // metrics are only logged if compilation is triggered.
137   Stage stage_ = Stage::kUnknown;
138   Status status_ = Status::kUnknown;
139 
140   int32_t primary_bcp_compilation_seconds_ = 0;
141   int32_t secondary_bcp_compilation_seconds_ = 0;
142   int32_t system_server_compilation_seconds_ = 0;
143   int32_t cache_space_free_start_mib_ = 0;
144   int32_t cache_space_free_end_mib_ = 0;
145 
146   friend class ScopedOdrCompilationTimer;
147 };
148 
149 // Timer used to measure compilation time (in seconds). Automatically associates the time recorded
150 // with the current stage of the metrics used.
151 class ScopedOdrCompilationTimer final {
152  public:
ScopedOdrCompilationTimer(OdrMetrics & metrics)153   explicit ScopedOdrCompilationTimer(OdrMetrics& metrics) :
154     metrics_(metrics), start_(std::chrono::steady_clock::now()) {}
155 
~ScopedOdrCompilationTimer()156   ~ScopedOdrCompilationTimer() {
157     auto elapsed_time = std::chrono::steady_clock::now() - start_;
158     auto elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(elapsed_time);
159     metrics_.SetCompilationTime(static_cast<int32_t>(elapsed_seconds.count()));
160   }
161 
162  private:
163   OdrMetrics& metrics_;
164   std::chrono::time_point<std::chrono::steady_clock> start_;
165 
166   DISALLOW_ALLOCATION();
167 };
168 
169 // Generated ostream operators.
170 std::ostream& operator<<(std::ostream& os, OdrMetrics::Status status);
171 std::ostream& operator<<(std::ostream& os, OdrMetrics::Stage stage);
172 std::ostream& operator<<(std::ostream& os, OdrMetrics::Trigger trigger);
173 
174 }  // namespace odrefresh
175 }  // namespace art
176 
177 #endif  // ART_ODREFRESH_ODR_METRICS_H_
178