| /* |
| * 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_RUNTIME_METRICS_REPORTER_H_ |
| #define ART_RUNTIME_METRICS_REPORTER_H_ |
| |
| #include "app_info.h" |
| #include "base/macros.h" |
| #include "base/message_queue.h" |
| #include "base/metrics/metrics.h" |
| |
| #pragma clang diagnostic push |
| #pragma clang diagnostic error "-Wconversion" |
| |
| namespace art HIDDEN { |
| namespace metrics { |
| |
| /** |
| * Encapsulates the specification of the metric reporting periods. |
| * |
| * The period spec follows the following regex: "(S,)?(\d+,)*\*?" |
| * with the following semantics: |
| * "S" - will only report at startup. |
| * |
| * "S,1,1" - will report startup, than 1 second later, then another |
| * second later. |
| * |
| * "S,1,2,4 " - will report at Startup time, then 1 seconds later, |
| * then 2, then finally 4 seconds later. After that, the |
| * reporting will stop. |
| * |
| * "S,1,2,4,*" - same as above, but after the final 4s period, the |
| * reporting will continue every other 4s. |
| * '*' is an indication we should report continuously |
| * every N seconds, where N is the last period. |
| * |
| * "2,*" - will report every 2 seconds |
| * |
| * Note that "", "*", or "S,*" are not valid specs, and 'S' can only occur |
| * in the beginning. |
| */ |
| struct ReportingPeriodSpec { |
| static std::optional<ReportingPeriodSpec> Parse( |
| const std::string& spec_str, std::string* error_msg); |
| |
| // The original spec. |
| std::string spec; |
| // The intervals when we should report. |
| std::vector<uint32_t> periods_seconds; |
| // Whether or not the reporting is continuous (contains a '*'). |
| bool continuous_reporting{false}; |
| // Whether or not the reporting should start after startup event (starts with an 'S'). |
| bool report_startup_first{false}; |
| }; |
| |
| // Defines the set of options for how metrics reporting happens. |
| struct ReportingConfig { |
| static ReportingConfig FromFlags(bool is_system_server = false); |
| |
| // Causes metrics to be written to the log, which makes them show up in logcat. |
| bool dump_to_logcat{false}; |
| |
| // Causes metrics to be written to statsd. |
| bool dump_to_statsd{false}; |
| |
| // If set, provides a file name to enable metrics logging to a file. |
| std::optional<std::string> dump_to_file; |
| |
| // Provides the desired output format for metrics written to a file. |
| std::string metrics_format; |
| |
| // The reporting period configuration. |
| std::optional<ReportingPeriodSpec> period_spec; |
| |
| // The mods that should report metrics. Together with reporting_num_mods, they |
| // dictate what percentage of the runtime execution will report metrics. |
| // If the `session_id (a random number) % reporting_num_mods < reporting_mods` |
| // then the runtime session will report metrics. |
| uint32_t reporting_mods{0}; |
| uint32_t reporting_num_mods{100}; |
| }; |
| |
| // MetricsReporter handles periodically reporting ART metrics. |
| class MetricsReporter { |
| public: |
| // Creates a MetricsReporter instance that matches the options selected in ReportingConfig. |
| static std::unique_ptr<MetricsReporter> Create(const ReportingConfig& config, Runtime* runtime); |
| |
| virtual ~MetricsReporter(); |
| |
| // Creates and runs the background reporting thread. |
| // |
| // Does nothing if the reporting config does not have any outputs enabled. |
| // |
| // Returns true if the thread was started, false otherwise. |
| bool MaybeStartBackgroundThread(SessionData session_data); |
| |
| // Sends a request to the background thread to shutdown. |
| void MaybeStopBackgroundThread(); |
| |
| // Causes metrics to be reported so we can see a snapshot of the metrics after app startup |
| // completes. |
| void NotifyStartupCompleted(); |
| |
| // Notifies the reporter that the app info was updated. This is used to detect / infer |
| // the compiler filter / reason of primary apks. |
| void NotifyAppInfoUpdated(AppInfo* app_info); |
| |
| // Requests a metrics report |
| // |
| // If synchronous is set to true, this function will block until the report has completed. |
| void RequestMetricsReport(bool synchronous = true); |
| |
| // Reloads the metrics config from the given value. |
| // Can only be called before starting the background thread. |
| void ReloadConfig(const ReportingConfig& config); |
| |
| void SetCompilationInfo(CompilationReason compilation_reason, |
| CompilerFilterReporting compiler_filter); |
| |
| static constexpr const char* kBackgroundThreadName = "Metrics Background Reporting Thread"; |
| |
| protected: |
| // Returns the metrics to be reported. |
| // This exists only for testing purposes so that we can verify reporting with minimum |
| // runtime interference. |
| virtual ArtMetrics* GetMetrics(); |
| |
| MetricsReporter(const ReportingConfig& config, Runtime* runtime); |
| |
| private: |
| // Whether or not we should reporting metrics according to the sampling rate. |
| bool IsMetricsReportingEnabled(const SessionData& session_data) const; |
| |
| // The background reporting thread main loop. |
| void BackgroundThreadRun(); |
| |
| // Calls messages_.SetTimeout if needed. |
| void MaybeResetTimeout(); |
| |
| // Outputs the current state of the metrics to the destination set by config_. |
| void ReportMetrics(); |
| |
| // Updates the session data in all the backends. |
| void UpdateSessionInBackends(); |
| |
| // Whether or not we should wait for startup before reporting for the first time. |
| bool ShouldReportAtStartup() const; |
| |
| // Whether or not we should continue reporting (either because we still |
| // have periods to report, or because we are in continuous mode). |
| bool ShouldContinueReporting() const; |
| |
| // Returns the next reporting period. |
| // Must be called only if ShouldContinueReporting() is true. |
| uint32_t GetNextPeriodSeconds(); |
| |
| ReportingConfig config_; |
| Runtime* runtime_; |
| std::vector<std::unique_ptr<MetricsBackend>> backends_; |
| std::optional<std::thread> thread_; |
| // Whether or not we reported the startup event. |
| bool startup_reported_; |
| // The index into period_spec.periods_seconds which tells the next delay in |
| // seconds for the next reporting. |
| uint32_t report_interval_index_; |
| |
| // A message indicating that the reporting thread should shut down. |
| struct ShutdownRequestedMessage {}; |
| |
| // A message indicating that app startup has completed. |
| struct StartupCompletedMessage {}; |
| |
| // A message requesting an explicit metrics report. |
| // |
| // The synchronous field specifies whether the reporting thread will send a message back when |
| // reporting is complete. |
| struct RequestMetricsReportMessage { |
| bool synchronous; |
| }; |
| |
| struct CompilationInfoMessage { |
| CompilationReason compilation_reason; |
| CompilerFilterReporting compiler_filter; |
| }; |
| |
| MessageQueue<ShutdownRequestedMessage, |
| StartupCompletedMessage, |
| RequestMetricsReportMessage, |
| CompilationInfoMessage> |
| messages_; |
| |
| // A message indicating a requested report has been finished. |
| struct ReportCompletedMessage {}; |
| |
| MessageQueue<ReportCompletedMessage> thread_to_host_messages_; |
| |
| SessionData session_data_{}; |
| bool session_started_{false}; |
| |
| friend class MetricsReporterTest; |
| }; |
| |
| } // namespace metrics |
| } // namespace art |
| |
| #pragma clang diagnostic pop // -Wconversion |
| |
| #endif // ART_RUNTIME_METRICS_REPORTER_H_ |