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_RUNTIME_METRICS_REPORTER_H_ 18 #define ART_RUNTIME_METRICS_REPORTER_H_ 19 20 #include "app_info.h" 21 #include "base/macros.h" 22 #include "base/message_queue.h" 23 #include "base/metrics/metrics.h" 24 25 #pragma clang diagnostic push 26 #pragma clang diagnostic error "-Wconversion" 27 28 namespace art HIDDEN { 29 namespace metrics { 30 31 /** 32 * Encapsulates the specification of the metric reporting periods. 33 * 34 * The period spec follows the following regex: "(S,)?(\d+,)*\*?" 35 * with the following semantics: 36 * "S" - will only report at startup. 37 * 38 * "S,1,1" - will report startup, than 1 second later, then another 39 * second later. 40 * 41 * "S,1,2,4 " - will report at Startup time, then 1 seconds later, 42 * then 2, then finally 4 seconds later. After that, the 43 * reporting will stop. 44 * 45 * "S,1,2,4,*" - same as above, but after the final 4s period, the 46 * reporting will continue every other 4s. 47 * '*' is an indication we should report continuously 48 * every N seconds, where N is the last period. 49 * 50 * "2,*" - will report every 2 seconds 51 * 52 * Note that "", "*", or "S,*" are not valid specs, and 'S' can only occur 53 * in the beginning. 54 */ 55 struct ReportingPeriodSpec { 56 static std::optional<ReportingPeriodSpec> Parse( 57 const std::string& spec_str, std::string* error_msg); 58 59 // The original spec. 60 std::string spec; 61 // The intervals when we should report. 62 std::vector<uint32_t> periods_seconds; 63 // Whether or not the reporting is continuous (contains a '*'). 64 bool continuous_reporting{false}; 65 // Whether or not the reporting should start after startup event (starts with an 'S'). 66 bool report_startup_first{false}; 67 }; 68 69 // Defines the set of options for how metrics reporting happens. 70 struct ReportingConfig { 71 static ReportingConfig FromFlags(bool is_system_server = false); 72 73 // Causes metrics to be written to the log, which makes them show up in logcat. 74 bool dump_to_logcat{false}; 75 76 // Causes metrics to be written to statsd. 77 bool dump_to_statsd{false}; 78 79 // If set, provides a file name to enable metrics logging to a file. 80 std::optional<std::string> dump_to_file; 81 82 // Provides the desired output format for metrics written to a file. 83 std::string metrics_format; 84 85 // The reporting period configuration. 86 std::optional<ReportingPeriodSpec> period_spec; 87 88 // The mods that should report metrics. Together with reporting_num_mods, they 89 // dictate what percentage of the runtime execution will report metrics. 90 // If the `session_id (a random number) % reporting_num_mods < reporting_mods` 91 // then the runtime session will report metrics. 92 uint32_t reporting_mods{0}; 93 uint32_t reporting_num_mods{100}; 94 }; 95 96 // MetricsReporter handles periodically reporting ART metrics. 97 class MetricsReporter { 98 public: 99 // Creates a MetricsReporter instance that matches the options selected in ReportingConfig. 100 static std::unique_ptr<MetricsReporter> Create(const ReportingConfig& config, Runtime* runtime); 101 102 virtual ~MetricsReporter(); 103 104 // Creates and runs the background reporting thread. 105 // 106 // Does nothing if the reporting config does not have any outputs enabled. 107 // 108 // Returns true if the thread was started, false otherwise. 109 bool MaybeStartBackgroundThread(SessionData session_data); 110 111 // Sends a request to the background thread to shutdown. 112 void MaybeStopBackgroundThread(); 113 114 // Causes metrics to be reported so we can see a snapshot of the metrics after app startup 115 // completes. 116 void NotifyStartupCompleted(); 117 118 // Notifies the reporter that the app info was updated. This is used to detect / infer 119 // the compiler filter / reason of primary apks. 120 void NotifyAppInfoUpdated(AppInfo* app_info); 121 122 // Requests a metrics report 123 // 124 // If synchronous is set to true, this function will block until the report has completed. 125 void RequestMetricsReport(bool synchronous = true); 126 127 // Reloads the metrics config from the given value. 128 // Can only be called before starting the background thread. 129 void ReloadConfig(const ReportingConfig& config); 130 131 void SetCompilationInfo(CompilationReason compilation_reason, 132 CompilerFilterReporting compiler_filter); 133 134 static constexpr const char* kBackgroundThreadName = "Metrics Background Reporting Thread"; 135 136 protected: 137 // Returns the metrics to be reported. 138 // This exists only for testing purposes so that we can verify reporting with minimum 139 // runtime interference. 140 virtual ArtMetrics* GetMetrics(); 141 142 MetricsReporter(const ReportingConfig& config, Runtime* runtime); 143 144 private: 145 // Whether or not we should reporting metrics according to the sampling rate. 146 bool IsMetricsReportingEnabled(const SessionData& session_data) const; 147 148 // The background reporting thread main loop. 149 void BackgroundThreadRun(); 150 151 // Calls messages_.SetTimeout if needed. 152 void MaybeResetTimeout(); 153 154 // Outputs the current state of the metrics to the destination set by config_. 155 void ReportMetrics(); 156 157 // Updates the session data in all the backends. 158 void UpdateSessionInBackends(); 159 160 // Whether or not we should wait for startup before reporting for the first time. 161 bool ShouldReportAtStartup() const; 162 163 // Whether or not we should continue reporting (either because we still 164 // have periods to report, or because we are in continuous mode). 165 bool ShouldContinueReporting() const; 166 167 // Returns the next reporting period. 168 // Must be called only if ShouldContinueReporting() is true. 169 uint32_t GetNextPeriodSeconds(); 170 171 ReportingConfig config_; 172 Runtime* runtime_; 173 std::vector<std::unique_ptr<MetricsBackend>> backends_; 174 std::optional<std::thread> thread_; 175 // Whether or not we reported the startup event. 176 bool startup_reported_; 177 // The index into period_spec.periods_seconds which tells the next delay in 178 // seconds for the next reporting. 179 uint32_t report_interval_index_; 180 181 // A message indicating that the reporting thread should shut down. 182 struct ShutdownRequestedMessage {}; 183 184 // A message indicating that app startup has completed. 185 struct StartupCompletedMessage {}; 186 187 // A message requesting an explicit metrics report. 188 // 189 // The synchronous field specifies whether the reporting thread will send a message back when 190 // reporting is complete. 191 struct RequestMetricsReportMessage { 192 bool synchronous; 193 }; 194 195 struct CompilationInfoMessage { 196 CompilationReason compilation_reason; 197 CompilerFilterReporting compiler_filter; 198 }; 199 200 MessageQueue<ShutdownRequestedMessage, 201 StartupCompletedMessage, 202 RequestMetricsReportMessage, 203 CompilationInfoMessage> 204 messages_; 205 206 // A message indicating a requested report has been finished. 207 struct ReportCompletedMessage {}; 208 209 MessageQueue<ReportCompletedMessage> thread_to_host_messages_; 210 211 SessionData session_data_{}; 212 bool session_started_{false}; 213 214 friend class MetricsReporterTest; 215 }; 216 217 } // namespace metrics 218 } // namespace art 219 220 #pragma clang diagnostic pop // -Wconversion 221 222 #endif // ART_RUNTIME_METRICS_REPORTER_H_ 223