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 // The reporting period configuration. 82 std::optional<ReportingPeriodSpec> period_spec; 83 84 // The mods that should report metrics. Together with reporting_num_mods, they 85 // dictate what percentage of the runtime execution will report metrics. 86 // If the `session_id (a random number) % reporting_num_mods < reporting_mods` 87 // then the runtime session will report metrics. 88 uint32_t reporting_mods{0}; 89 uint32_t reporting_num_mods{100}; 90 }; 91 92 // MetricsReporter handles periodically reporting ART metrics. 93 class MetricsReporter { 94 public: 95 // Creates a MetricsReporter instance that matches the options selected in ReportingConfig. 96 static std::unique_ptr<MetricsReporter> Create(const ReportingConfig& config, Runtime* runtime); 97 98 virtual ~MetricsReporter(); 99 100 // Creates and runs the background reporting thread. 101 // 102 // Does nothing if the reporting config does not have any outputs enabled. 103 // 104 // Returns true if the thread was started, false otherwise. 105 bool MaybeStartBackgroundThread(SessionData session_data); 106 107 // Sends a request to the background thread to shutdown. 108 void MaybeStopBackgroundThread(); 109 110 // Causes metrics to be reported so we can see a snapshot of the metrics after app startup 111 // completes. 112 void NotifyStartupCompleted(); 113 114 // Notifies the reporter that the app info was updated. This is used to detect / infer 115 // the compiler filter / reason of primary apks. 116 void NotifyAppInfoUpdated(AppInfo* app_info); 117 118 // Requests a metrics report 119 // 120 // If synchronous is set to true, this function will block until the report has completed. 121 void RequestMetricsReport(bool synchronous = true); 122 123 // Reloads the metrics config from the given value. 124 // Can only be called before starting the background thread. 125 void ReloadConfig(const ReportingConfig& config); 126 127 void SetCompilationInfo(CompilationReason compilation_reason, 128 CompilerFilterReporting compiler_filter); 129 130 static constexpr const char* kBackgroundThreadName = "Metrics Background Reporting Thread"; 131 132 protected: 133 // Returns the metrics to be reported. 134 // This exists only for testing purposes so that we can verify reporting with minimum 135 // runtime interference. 136 virtual const ArtMetrics* GetMetrics(); 137 138 MetricsReporter(const ReportingConfig& config, Runtime* runtime); 139 140 private: 141 // Whether or not we should reporting metrics according to the sampling rate. 142 bool IsMetricsReportingEnabled(const SessionData& session_data) const; 143 144 // The background reporting thread main loop. 145 void BackgroundThreadRun(); 146 147 // Calls messages_.SetTimeout if needed. 148 void MaybeResetTimeout(); 149 150 // Outputs the current state of the metrics to the destination set by config_. 151 void ReportMetrics(); 152 153 // Updates the session data in all the backends. 154 void UpdateSessionInBackends(); 155 156 // Whether or not we should wait for startup before reporting for the first time. 157 bool ShouldReportAtStartup() const; 158 159 // Whether or not we should continue reporting (either because we still 160 // have periods to report, or because we are in continuous mode). 161 bool ShouldContinueReporting() const; 162 163 // Returns the next reporting period. 164 // Must be called only if ShouldContinueReporting() is true. 165 uint32_t GetNextPeriodSeconds(); 166 167 ReportingConfig config_; 168 Runtime* runtime_; 169 std::vector<std::unique_ptr<MetricsBackend>> backends_; 170 std::optional<std::thread> thread_; 171 // Whether or not we reported the startup event. 172 bool startup_reported_; 173 // The index into period_spec.periods_seconds which tells the next delay in 174 // seconds for the next reporting. 175 uint32_t report_interval_index_; 176 177 // A message indicating that the reporting thread should shut down. 178 struct ShutdownRequestedMessage {}; 179 180 // A message indicating that app startup has completed. 181 struct StartupCompletedMessage {}; 182 183 // A message requesting an explicit metrics report. 184 // 185 // The synchronous field specifies whether the reporting thread will send a message back when 186 // reporting is complete. 187 struct RequestMetricsReportMessage { 188 bool synchronous; 189 }; 190 191 struct CompilationInfoMessage { 192 CompilationReason compilation_reason; 193 CompilerFilterReporting compiler_filter; 194 }; 195 196 MessageQueue<ShutdownRequestedMessage, 197 StartupCompletedMessage, 198 RequestMetricsReportMessage, 199 CompilationInfoMessage> 200 messages_; 201 202 // A message indicating a requested report has been finished. 203 struct ReportCompletedMessage {}; 204 205 MessageQueue<ReportCompletedMessage> thread_to_host_messages_; 206 207 SessionData session_data_{}; 208 bool session_started_{false}; 209 210 friend class MetricsReporterTest; 211 }; 212 213 } // namespace metrics 214 } // namespace art 215 216 #pragma clang diagnostic pop // -Wconversion 217 218 #endif // ART_RUNTIME_METRICS_REPORTER_H_ 219