Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  reporter.cc

  Sprache: C
 

/*
 * 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.
 */


#include "reporter.h"

#include <android-base/parseint.h>

#include <algorithm>

#include "base/flags.h"
#include "base/stl_util.h"
#include "oat/oat_file_manager.h"
#include "runtime.h"
#include "runtime_options.h"
#include "statsd.h"
#include "thread-current-inl.h"

#pragma clang diagnostic push
#pragma clang diagnostic error "-Wconversion"

namespace art HIDDEN {
namespace metrics {

std::unique_ptr<MetricsReporter> MetricsReporter::Create(
    const ReportingConfig& config, Runtime* runtime) {
  // We can't use std::make_unique here because the MetricsReporter constructor is private.
  return std::unique_ptr<MetricsReporter>{new MetricsReporter{std::move(config), runtime}};
}

MetricsReporter::MetricsReporter(const ReportingConfig& config, Runtime* runtime)
    : config_{config},
      runtime_{runtime},
      startup_reported_{false},
      report_interval_index_{0} {}

MetricsReporter::~MetricsReporter() { MaybeStopBackgroundThread(); }

void MetricsReporter::ReloadConfig(const ReportingConfig& config) {
  DCHECK(!thread_.has_value()) << "The config cannot be reloaded after the background "
                                  "reporting thread is started.";
  config_ = config;
}

bool MetricsReporter::IsMetricsReportingEnabled(const SessionData& session_dataconst {
  return session_data.session_id % config_.reporting_num_mods < config_.reporting_mods;
}

bool MetricsReporter::MaybeStartBackgroundThread(SessionData session_data) {
  CHECK(!thread_.has_value());

  session_data_ = session_data;
  LOG_STREAM(DEBUG) << "Received session metadata: " << session_data_.session_id;

  if (!IsMetricsReportingEnabled(session_data_)) {
    return false;
  }

  thread_.emplace(&MetricsReporter::BackgroundThreadRun, this);
  return true;
}

void MetricsReporter::MaybeStopBackgroundThread() {
  if (thread_.has_value()) {
    messages_.SendMessage(ShutdownRequestedMessage{});
    thread_->join();
    thread_.reset();
  }
}

void MetricsReporter::NotifyStartupCompleted() {
  if (ShouldReportAtStartup() && thread_.has_value()) {
    messages_.SendMessage(StartupCompletedMessage{});
  }
}

void MetricsReporter::NotifyAppInfoUpdated(AppInfo* app_info) {
  std::string compilation_reason;
  std::string compiler_filter;

  app_info->GetPrimaryApkOptimizationStatus(
      &compiler_filter, &compilation_reason);

  SetCompilationInfo(
      CompilationReasonFromName(compilation_reason),
      CompilerFilterReportingFromName(compiler_filter));
}

void MetricsReporter::RequestMetricsReport(bool synchronous) {
  if (thread_.has_value()) {
    messages_.SendMessage(RequestMetricsReportMessage{synchronous});
    if (synchronous) {
      thread_to_host_messages_.ReceiveMessage();
    }
  }
}

void MetricsReporter::SetCompilationInfo(CompilationReason compilation_reason,
                                         CompilerFilterReporting compiler_filter) {
  if (thread_.has_value()) {
    messages_.SendMessage(CompilationInfoMessage{compilation_reason, compiler_filter});
  }
}

void MetricsReporter::BackgroundThreadRun() {
  LOG_STREAM(DEBUG) << "Metrics reporting thread started";

  // AttachCurrentThread is needed so we can safely use the ART concurrency primitives within the
  // messages_ MessageQueue.
  const bool attached = runtime_->AttachCurrentThread(kBackgroundThreadName,
                                                      /*as_daemon=*/true,
                                                      runtime_->GetSystemThreadGroup(),
                                                      /*create_peer=*/true);

  if (attached) {
    // Mark it as rutime thread so we won't report it via jvmti.
    Thread::Current()->SetIsRuntimeThread(true);
  }

  bool running = true;

  // Configure the backends
  if (config_.dump_to_logcat) {
    backends_.emplace_back(new LogBackend(std::make_unique<TextFormatter>(), LogSeverity::INFO));
  }
  if (config_.dump_to_file.has_value()) {
    std::unique_ptr<MetricsFormatter> formatter;
    if (config_.metrics_format == "xml") {
      formatter = std::make_unique<XmlFormatter>();
    } else {
      formatter = std::make_unique<TextFormatter>();
    }

    backends_.emplace_back(new FileBackend(std::move(formatter), config_.dump_to_file.value()));
  }
  if (config_.dump_to_statsd) {
    auto backend = CreateStatsdBackend();
    if (backend != nullptr) {
      backends_.emplace_back(std::move(backend));
    }
  }

  MaybeResetTimeout();

  while (running) {
    messages_.SwitchReceive(
        [&]([[maybe_unused]] ShutdownRequestedMessage message) {
          LOG_STREAM(DEBUG) << "Shutdown request received " << session_data_.session_id;
          running = false;

          ReportMetrics();
        },
        [&](RequestMetricsReportMessage message) {
          LOG_STREAM(DEBUG) << "Explicit report request received " << session_data_.session_id;
          ReportMetrics();
          if (message.synchronous) {
            thread_to_host_messages_.SendMessage(ReportCompletedMessage{});
          }
        },
        [&]([[maybe_unused]] TimeoutExpiredMessage message) {
          LOG_STREAM(DEBUG) << "Timer expired, reporting metrics " << session_data_.session_id;

          ReportMetrics();
          MaybeResetTimeout();
        },
        [&]([[maybe_unused]] StartupCompletedMessage message) {
          LOG_STREAM(DEBUG) << "App startup completed, reporting metrics "
              << session_data_.session_id;
          ReportMetrics();
          startup_reported_ = true;
          MaybeResetTimeout();
        },
        [&](CompilationInfoMessage message) {
          LOG_STREAM(DEBUG) << "Compilation info received " << session_data_.session_id;
          session_data_.compilation_reason = message.compilation_reason;
          session_data_.compiler_filter = message.compiler_filter;

          UpdateSessionInBackends();
        });
  }

  if (attached) {
    runtime_->DetachCurrentThread();
  }
  LOG_STREAM(DEBUG) << "Metrics reporting thread terminating " << session_data_.session_id;
}

void MetricsReporter::MaybeResetTimeout() {
  if (ShouldContinueReporting()) {
    messages_.SetTimeout(SecondsToMs(GetNextPeriodSeconds()));
  }
}

ArtMetrics* MetricsReporter::GetMetrics() { return runtime_->GetMetrics(); }

void MetricsReporter::ReportMetrics() {
  ArtMetrics* metrics = GetMetrics();

  if (!session_started_) {
    for (auto& backend : backends_) {
      backend->BeginOrUpdateSession(session_data_);
    }
    session_started_ = true;
  }

  metrics->ReportAllMetricsAndResetValueMetrics(MakeNonOwningPointerVector(backends_));
}

void MetricsReporter::UpdateSessionInBackends() {
  if (session_started_) {
    for (auto& backend : backends_) {
      backend->BeginOrUpdateSession(session_data_);
    }
  }
}

bool MetricsReporter::ShouldReportAtStartup() const {
  return IsMetricsReportingEnabled(session_data_) &&
      config_.period_spec.has_value() &&
      config_.period_spec->report_startup_first;
}

bool MetricsReporter::ShouldContinueReporting() const {
  bool result =
      // Only if the reporting is enabled
      IsMetricsReportingEnabled(session_data_) &&
      // and if we have period spec
      config_.period_spec.has_value() &&
      // and the periods are non empty
      !config_.period_spec->periods_seconds.empty() &&
      // and we already reported startup or not required to report startup
      (startup_reported_ || !config_.period_spec->report_startup_first) &&
      // and we still have unreported intervals or we are asked to report continuously.
      (config_.period_spec->continuous_reporting ||
              (report_interval_index_ < config_.period_spec->periods_seconds.size()));
  return result;
}

uint32_t MetricsReporter::GetNextPeriodSeconds() {
  DCHECK(ShouldContinueReporting());

  // The index is either the current report_interval_index or the last index
  // if we are in continuous mode and reached the end.
  uint32_t index = std::min(
      report_interval_index_,
      static_cast<uint32_t>(config_.period_spec->periods_seconds.size() - 1));

  uint32_t result = config_.period_spec->periods_seconds[index];

  // Advance the index if we didn't get to the end.
  if (report_interval_index_ < config_.period_spec->periods_seconds.size()) {
    report_interval_index_++;
  }
  return result;
}

ReportingConfig ReportingConfig::FromFlags(bool is_system_server) {
  std::optional<std::string> spec_str = is_system_server
      ? gFlags.MetricsReportingSpecSystemServer.GetValueOptional()
      : gFlags.MetricsReportingSpec.GetValueOptional();

  std::optional<ReportingPeriodSpec> period_spec = std::nullopt;

  if (spec_str.has_value()) {
    std::string error;
    period_spec = ReportingPeriodSpec::Parse(spec_str.value(), &error);
    if (!period_spec.has_value()) {
      LOG(ERROR) << "Failed to create metrics reporting spec from: " << spec_str.value()
          << " with error: " << error;
    }
  }

  uint32_t reporting_num_mods = is_system_server
      ? gFlags.MetricsReportingNumModsServer()
      : gFlags.MetricsReportingNumMods();
  uint32_t reporting_mods = is_system_server
      ? gFlags.MetricsReportingModsServer()
      : gFlags.MetricsReportingMods();

  if (reporting_mods > reporting_num_mods || reporting_num_mods == 0) {
    LOG(ERROR) << "Invalid metrics reporting mods: " << reporting_mods
        << " num modes=" << reporting_num_mods
        << ". The reporting is disabled";
    reporting_mods = 0;
    reporting_num_mods = 100;
  }

  return {
      .dump_to_logcat = gFlags.MetricsWriteToLogcat(),
      .dump_to_statsd = gFlags.MetricsWriteToStatsd(),
      .dump_to_file = gFlags.MetricsWriteToFile.GetValueOptional(),
      .metrics_format = gFlags.MetricsFormat(),
      .period_spec = period_spec,
      .reporting_mods = reporting_mods,
      .reporting_num_mods = reporting_num_mods,
  };
}

std::optional<ReportingPeriodSpec> ReportingPeriodSpec::Parse(
    const std::string& spec_str, std::string* error_msg) {
  *error_msg = "";
  if (spec_str.empty()) {
    *error_msg = "Invalid empty spec.";
    return std::nullopt;
  }

  // Split the string. Each element is separated by comma.
  std::vector<std::string> elems;
  Split(spec_str, ',', &elems);

  // Check the startup marker (front) and the continuous one (back).
  std::optional<ReportingPeriodSpec> spec = std::make_optional(ReportingPeriodSpec());
  spec->spec = spec_str;
  spec->report_startup_first = elems.front() == "S";
  spec->continuous_reporting = elems.back() == "*";

  // Compute the indices for the period values.
  size_t start_interval_idx = spec->report_startup_first ? 1 : 0;
  size_t end_interval_idx = spec->continuous_reporting ? (elems.size() - 1) : elems.size();

  // '*' needs a numeric interval before in order to be valid.
  if (spec->continuous_reporting &&
      end_interval_idx == start_interval_idx) {
    *error_msg = "Invalid period value in spec: " + spec_str;
    return std::nullopt;
  }

  // Parse the periods.
  for (size_t i = start_interval_idx; i < end_interval_idx; i++) {
    uint32_t period;
    if (!android::base::ParseUint(elems[i], &period)) {
        *error_msg = "Invalid period value in spec: " + spec_str;
        return std::nullopt;
    }
    spec->periods_seconds.push_back(period);
  }

  return spec;
}

}  // namespace metrics
}  // namespace art

#pragma clang diagnostic pop  // -Wconversion

Messung V0.5 in Prozent
C=88 H=95 G=91

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik