| /* |
| * 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. |
| */ |
| |
| #ifndef ART_ODREFRESH_ODR_METRICS_H_ |
| #define ART_ODREFRESH_ODR_METRICS_H_ |
| |
| #include <chrono> |
| #include <cstdint> |
| #include <iosfwd> |
| #include <optional> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "exec_utils.h" |
| #include "odr_metrics_record.h" |
| |
| namespace art { |
| namespace odrefresh { |
| |
| class OdrMetrics final { |
| public: |
| // Enumeration used to track the latest stage reached running odrefresh. |
| // |
| // These values mirror those in OdrefreshReported::Stage in frameworks/proto_logging/atoms.proto. |
| // NB There are gaps between the values in case an additional stages are introduced. |
| enum class Stage : uint8_t { |
| kUnknown = 0, |
| kCheck = 10, |
| kPreparation = 20, |
| kPrimaryBootClasspath = 30, |
| kSecondaryBootClasspath = 40, |
| kSystemServerClasspath = 50, |
| kComplete = 60, |
| }; |
| |
| // Enumeration describing the overall status, processing stops on the first error discovered. |
| // |
| // These values mirror those in OdrefreshReported::Status in frameworks/proto_logging/atoms.proto. |
| enum class Status : uint8_t { |
| kUnknown = 0, |
| kOK = 1, |
| kNoSpace = 2, |
| kIoError = 3, |
| kDex2OatError = 4, |
| // Value 5 was kTimeLimitExceeded, but has been removed in favour of |
| // reporting the exit code for Dex2Oat (set to ExecResult::kTimedOut) |
| kStagingFailed = 6, |
| kInstallFailed = 7, |
| // Failed to access the dalvik-cache directory due to lack of permission. |
| kDalvikCachePermissionDenied = 8, |
| }; |
| |
| // Enumeration describing the cause of compilation (if any) in odrefresh. |
| // |
| // These values mirror those in OdrefreshReported::Trigger in |
| // frameworks/proto_logging/atoms.proto. |
| enum class Trigger : uint8_t { |
| kUnknown = 0, |
| kApexVersionMismatch = 1, |
| kDexFilesChanged = 2, |
| kMissingArtifacts = 3, |
| }; |
| |
| explicit OdrMetrics(const std::string& cache_directory, |
| const std::string& metrics_file = kOdrefreshMetricsFile); |
| ~OdrMetrics(); |
| |
| // Enables/disables metrics writing. |
| void SetEnabled(bool value) { enabled_ = value; } |
| |
| // Gets the ART APEX that metrics are being collected on behalf of. |
| int64_t GetArtApexVersion() const { return art_apex_version_; } |
| |
| // Sets the ART APEX that metrics are being collected on behalf of. |
| void SetArtApexVersion(int64_t version) { art_apex_version_ = version; } |
| |
| // Gets the ART APEX last update time in milliseconds. |
| int64_t GetArtApexLastUpdateMillis() const { return art_apex_last_update_millis_; } |
| |
| // Sets the ART APEX last update time in milliseconds. |
| void SetArtApexLastUpdateMillis(int64_t last_update_millis) { |
| art_apex_last_update_millis_ = last_update_millis; |
| } |
| |
| // Gets the trigger for metrics collection. The trigger is the reason why odrefresh considers |
| // compilation necessary. |
| Trigger GetTrigger() const { return trigger_; } |
| |
| // Sets the trigger for metrics collection. The trigger is the reason why odrefresh considers |
| // compilation necessary. Only call this method if compilation is necessary as the presence |
| // of a trigger means we will try to record and upload metrics. |
| void SetTrigger(const Trigger trigger) { trigger_ = trigger; } |
| |
| // Sets the execution status of the current odrefresh processing stage. |
| void SetStatus(const Status status) { status_ = status; } |
| |
| // Sets the current odrefresh processing stage. |
| void SetStage(Stage stage) { stage_ = stage; } |
| |
| // Sets the result of the current dex2oat invocation. |
| void SetDex2OatResult(const ExecResult& dex2oat_result); |
| |
| // Captures the current free space as the end free space. |
| void CaptureSpaceFreeEnd(); |
| |
| // Records metrics into an OdrMetricsRecord. |
| OdrMetricsRecord ToRecord() const; |
| |
| private: |
| OdrMetrics(const OdrMetrics&) = delete; |
| OdrMetrics operator=(const OdrMetrics&) = delete; |
| |
| static int32_t GetFreeSpaceMiB(const std::string& path); |
| static void WriteToFile(const std::string& path, const OdrMetrics* metrics); |
| |
| void SetCompilationTime(int32_t millis); |
| static OdrMetricsRecord::Dex2OatExecResult |
| ConvertExecResult(const std::optional<ExecResult>& result); |
| |
| const std::string cache_directory_; |
| const std::string metrics_file_; |
| |
| bool enabled_ = false; |
| |
| int64_t art_apex_version_ = 0; |
| int64_t art_apex_last_update_millis_ = 0; |
| Trigger trigger_ = Trigger::kUnknown; |
| Stage stage_ = Stage::kUnknown; |
| Status status_ = Status::kUnknown; |
| |
| int32_t cache_space_free_start_mib_ = 0; |
| int32_t cache_space_free_end_mib_ = 0; |
| |
| // The total time spent on compiling primary BCP. |
| int32_t primary_bcp_compilation_millis_ = 0; |
| |
| // The result of the dex2oat invocation for compiling primary BCP, or `std::nullopt` if dex2oat is |
| // not invoked. |
| std::optional<ExecResult> primary_bcp_dex2oat_result_; |
| |
| // The total time spent on compiling secondary BCP. |
| int32_t secondary_bcp_compilation_millis_ = 0; |
| |
| // The result of the dex2oat invocation for compiling secondary BCP, or `std::nullopt` if dex2oat |
| // is not invoked. |
| std::optional<ExecResult> secondary_bcp_dex2oat_result_; |
| |
| // The total time spent on compiling system server. |
| int32_t system_server_compilation_millis_ = 0; |
| |
| // The result of the last dex2oat invocation for compiling system server, or `std::nullopt` if |
| // dex2oat is not invoked. |
| std::optional<ExecResult> system_server_dex2oat_result_; |
| |
| friend class ScopedOdrCompilationTimer; |
| }; |
| |
| // Timer used to measure compilation time (in seconds). Automatically associates the time recorded |
| // with the current stage of the metrics used. |
| class ScopedOdrCompilationTimer final { |
| public: |
| explicit ScopedOdrCompilationTimer(OdrMetrics& metrics) : |
| metrics_(metrics), start_(std::chrono::steady_clock::now()) {} |
| |
| ~ScopedOdrCompilationTimer() { |
| auto elapsed_time = std::chrono::steady_clock::now() - start_; |
| auto elapsed_millis = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time); |
| metrics_.SetCompilationTime(static_cast<int32_t>(elapsed_millis.count())); |
| } |
| |
| private: |
| OdrMetrics& metrics_; |
| std::chrono::time_point<std::chrono::steady_clock> start_; |
| |
| DISALLOW_ALLOCATION(); |
| }; |
| |
| // Generated ostream operators. |
| std::ostream& operator<<(std::ostream& os, OdrMetrics::Status status); |
| std::ostream& operator<<(std::ostream& os, OdrMetrics::Stage stage); |
| std::ostream& operator<<(std::ostream& os, OdrMetrics::Trigger trigger); |
| |
| } // namespace odrefresh |
| } // namespace art |
| |
| #endif // ART_ODREFRESH_ODR_METRICS_H_ |