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