summaryrefslogtreecommitdiff
path: root/odrefresh/odr_metrics.h
blob: cd80beffc5b5b45425506c2f5fe338ad19c4e99e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 * 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 "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,
    kTimeLimitExceeded = 5,
    kStagingFailed = 6,
    kInstallFailed = 7,
  };

  // 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();

  // 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_.has_value() ? trigger_.value() : Trigger::kUnknown;
  }

  // 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);

  // Record metrics into an OdrMetricsRecord.
  // returns true on success, false if instance is not valid (because the trigger value is not set).
  bool ToRecord(/*out*/OdrMetricsRecord* record) 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 seconds);

  const std::string cache_directory_;
  const std::string metrics_file_;

  int64_t art_apex_version_ = 0;
  int64_t art_apex_last_update_millis_ = 0;
  std::optional<Trigger> trigger_ = {};  // metrics are only logged if compilation is triggered.
  Stage stage_ = Stage::kUnknown;
  Status status_ = Status::kUnknown;

  int32_t primary_bcp_compilation_seconds_ = 0;
  int32_t secondary_bcp_compilation_seconds_ = 0;
  int32_t system_server_compilation_seconds_ = 0;
  int32_t cache_space_free_start_mib_ = 0;
  int32_t cache_space_free_end_mib_ = 0;

  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_seconds = std::chrono::duration_cast<std::chrono::seconds>(elapsed_time);
    metrics_.SetCompilationTime(static_cast<int32_t>(elapsed_seconds.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_