summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Holk <eholk@google.com> 2021-01-13 20:38:34 +0000
committer Treehugger Robot <treehugger-gerrit@google.com> 2021-01-14 21:39:16 +0000
commit5bb354fa440ae7c9ebe6994ceb45e6795c5d3363 (patch)
tree166f2719d86826c33b8b2e541c4bda8ee9caa93f
parentec389671c661ea1cb73490a2896d6519f299dea2 (diff)
Revert^4 "[metrics] Add file output support"
Adds a new command line option, -Xwrite-metrics-to-file=_, which specifies a file for writing metrics to. This can be used in conjunction with -Xwrite-metrics-to-log, which will cause the output to go to both logcat and the file. Writing metrics to a file can be helpful for testing or benchmarking environments. Access to the file is protected using advisory locking, so it is safe to have multiple processes write metrics to the same file. This reverts commit f8567b535dcc4618f0ee76e5b8716d296681197b. Reason for revert: Splitting out problematic test. Test: test/run-test --host test/2234-write-metrics-to-file Bug: 175025360 Bug: 170149255 Change-Id: I09be3bfe10293fe71ded1a5b155dcd2fd226f8b3
-rw-r--r--libartbase/base/variant_map.h8
-rw-r--r--runtime/metrics/metrics.cc39
-rw-r--r--runtime/metrics/metrics.h18
-rw-r--r--runtime/parsed_options.cc5
-rw-r--r--runtime/runtime.cc17
-rw-r--r--runtime/runtime.h1
-rw-r--r--runtime/runtime_options.def1
7 files changed, 74 insertions, 15 deletions
diff --git a/libartbase/base/variant_map.h b/libartbase/base/variant_map.h
index 581bc234cc..7349bbc046 100644
--- a/libartbase/base/variant_map.h
+++ b/libartbase/base/variant_map.h
@@ -229,6 +229,14 @@ struct VariantMap {
return GetValuePtr(key);
}
+ // Look up the value from the key and return the value wrapped in a std::optional. If it was not
+ // set in the map, return an empty std::optional.
+ template <typename TValue>
+ std::optional<TValue> GetOptional(const TKey<TValue>& key) const {
+ auto* ptr = Get(key);
+ return (ptr == nullptr) ? std::optional<TValue>{} : std::make_optional(*ptr);
+ }
+
// Lookup the value from the key. If it was not set in the map, return the default value.
// The default value is either the key's default, or TValue{} if the key doesn't have a default.
template <typename TValue>
diff --git a/runtime/metrics/metrics.cc b/runtime/metrics/metrics.cc
index 81ae2b4dab..e85897b19e 100644
--- a/runtime/metrics/metrics.cc
+++ b/runtime/metrics/metrics.cc
@@ -16,12 +16,20 @@
#include "metrics.h"
+#include <sstream>
+
+#include "android-base/file.h"
#include "android-base/logging.h"
#include "base/macros.h"
+#include "base/scoped_flock.h"
+#include "runtime.h"
+#include "runtime_options.h"
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wconversion"
+using android::base::WriteStringToFd;
+
namespace art {
namespace metrics {
@@ -116,15 +124,15 @@ std::unique_ptr<MetricsReporter> MetricsReporter::Create(ReportingConfig config,
std::unique_ptr<MetricsBackend> backend;
// We can't use std::make_unique here because the MetricsReporter constructor is private.
- return std::unique_ptr<MetricsReporter>{new MetricsReporter{config, metrics}};
+ return std::unique_ptr<MetricsReporter>{new MetricsReporter{std::move(config), metrics}};
}
MetricsReporter::MetricsReporter(ReportingConfig config, const ArtMetrics* metrics)
- : config_{config}, metrics_{metrics} {}
+ : config_{std::move(config)}, metrics_{metrics} {}
MetricsReporter::~MetricsReporter() {
// If we are configured to report metrics, do one final report at the end.
- if (config_.dump_to_logcat) {
+ if (config_.ReportingEnabled()) {
LOG_STREAM(INFO) << "\n*** ART internal metrics ***\n\n";
// LOG_STREAM(INFO) destroys the stream at the end of the statement, which makes it tricky pass
// it to store as a field in StreamBackend. To get around this, we use an immediately-invoked
@@ -136,6 +144,31 @@ MetricsReporter::~MetricsReporter() {
}(LOG_STREAM(INFO));
LOG_STREAM(INFO) << "\n*** Done dumping ART internal metrics ***\n";
}
+ if (config_.dump_to_file.has_value()) {
+ const auto& filename = config_.dump_to_file.value();
+ std::ostringstream stream;
+ StreamBackend backend{stream};
+ metrics_->ReportAllMetrics(&backend);
+
+ std::string error_message;
+ auto file{
+ LockedFile::Open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, true, &error_message)};
+ if (file.get() == nullptr) {
+ LOG(WARNING) << "Could open metrics file '" << filename << "': " << error_message;
+ } else {
+ if (!WriteStringToFd(stream.str(), file.get()->Fd())) {
+ PLOG(WARNING) << "Error writing metrics to file";
+ }
+ }
+ }
+}
+
+ReportingConfig ReportingConfig::FromRuntimeArguments(const RuntimeArgumentMap& args) {
+ using M = RuntimeArgumentMap;
+ return {
+ .dump_to_logcat = args.Exists(M::WriteMetricsToLog),
+ .dump_to_file = args.GetOptional(M::WriteMetricsToFile),
+ };
}
} // namespace metrics
diff --git a/runtime/metrics/metrics.h b/runtime/metrics/metrics.h
index 7156d576e0..a6e395559a 100644
--- a/runtime/metrics/metrics.h
+++ b/runtime/metrics/metrics.h
@@ -21,6 +21,7 @@
#include <array>
#include <atomic>
+#include <optional>
#include <ostream>
#include <string_view>
#include <vector>
@@ -58,6 +59,10 @@
// per metric.
namespace art {
+
+class Runtime;
+struct RuntimeArgumentMap;
+
namespace metrics {
/**
@@ -340,9 +345,16 @@ class ArtMetrics {
std::string DatumName(DatumId datum);
struct ReportingConfig {
- bool dump_to_logcat;
- // TODO(eholk): this will grow to support other configurations, such as logging to a file, or
- // statsd. There will also be options for reporting after a period of time, or at certain events.
+ static ReportingConfig FromRuntimeArguments(const RuntimeArgumentMap& args);
+
+ // Causes metrics to be written to the log, which makes them show up in logcat.
+ bool dump_to_logcat{false};
+
+ // If set, provides a file name to enable metrics logging to a file.
+ std::optional<std::string> dump_to_file;
+
+ // Returns whether any options are set that enables metrics reporting.
+ constexpr bool ReportingEnabled() const { return dump_to_logcat || dump_to_file.has_value(); }
};
// MetricsReporter handles periodically reporting ART metrics.
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 508e697f7f..5b8c9d3bc1 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -395,7 +395,12 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.Define("-Xuse-stderr-logger")
.IntoKey(M::UseStderrLogger)
.Define("-Xwrite-metrics-to-log")
+ .WithHelp("Enables writing ART metrics to logcat")
.IntoKey(M::WriteMetricsToLog)
+ .Define("-Xwrite-metrics-to-file=_")
+ .WithHelp("Enables writing ART metrics to the given file")
+ .WithType<std::string>()
+ .IntoKey(M::WriteMetricsToFile)
.Define("-Xonly-use-system-oat-files")
.IntoKey(M::OnlyUseSystemOatFiles)
.Define("-Xverifier-logging-threshold=_")
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2012a0492b..00d9ff1414 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -223,13 +223,6 @@ void CheckConstants() {
CHECK_EQ(mirror::Array::kFirstElementOffset, mirror::Array::FirstElementOffset());
}
-metrics::ReportingConfig ParseMetricsReportingConfig(const RuntimeArgumentMap& args) {
- using M = RuntimeArgumentMap;
- return {
- .dump_to_logcat = args.Exists(M::WriteMetricsToLog),
- };
-}
-
} // namespace
Runtime::Runtime()
@@ -1719,8 +1712,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
// Class-roots are setup, we can now finish initializing the JniIdManager.
GetJniIdManager()->Init(self);
- metrics_reporter_ =
- metrics::MetricsReporter::Create(ParseMetricsReportingConfig(runtime_options), &metrics_);
+ InitMetrics(runtime_options);
// Runtime initialization is largely done now.
// We load plugins first since that can modify the runtime state slightly.
@@ -1820,6 +1812,13 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
return true;
}
+void Runtime::InitMetrics(const RuntimeArgumentMap& runtime_options) {
+ auto metrics_config = metrics::ReportingConfig::FromRuntimeArguments(runtime_options);
+ if (metrics_config.ReportingEnabled()) {
+ metrics_reporter_ = metrics::MetricsReporter::Create(metrics_config, GetMetrics());
+ }
+}
+
bool Runtime::EnsurePluginLoaded(const char* plugin_name, std::string* error_msg) {
// Is the plugin already loaded?
for (const Plugin& p : plugins_) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 7fd731eb0d..06f05a177e 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -980,6 +980,7 @@ class Runtime {
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_);
void InitNativeMethods() REQUIRES(!Locks::mutator_lock_);
void RegisterRuntimeNativeMethods(JNIEnv* env);
+ void InitMetrics(const RuntimeArgumentMap& runtime_options);
void StartDaemonThreads();
void StartSignalCatcher();
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 4462de22f5..80ec30833f 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -185,5 +185,6 @@ RUNTIME_OPTIONS_KEY (bool, PerfettoHprof, false)
// Whether to dump ART metrics to logcat
RUNTIME_OPTIONS_KEY (Unit, WriteMetricsToLog)
+RUNTIME_OPTIONS_KEY (std::string, WriteMetricsToFile)
#undef RUNTIME_OPTIONS_KEY