blob: 8e10622d12300673a3774e668981cd1868b9e51f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/zx/time.h>
#include <lib/zx/vmo.h>
#include <unistd.h>
#include <utility>
#include <cobalt-client/cpp/collector.h>
#include <cobalt-client/cpp/counter.h>
#include <cobalt-client/cpp/histogram.h>
#include <cobalt-client/cpp/in_memory_logger.h>
#include <fs/metrics/cobalt_metrics.h>
#include <zxtest/zxtest.h>
namespace fs_metrics {
namespace {
// Observed latency.
constexpr uint32_t kLatencyNs = 5000;
constexpr uint32_t kBuckets = 20;
std::unique_ptr<cobalt_client::Collector> MakeCollector(
cobalt_client::InMemoryLogger** logger = nullptr) {
auto logger_ptr = std::make_unique<cobalt_client::InMemoryLogger>();
if (logger != nullptr) {
*logger = logger_ptr.get();
}
return std::make_unique<cobalt_client::Collector>(std::move(logger_ptr));
}
cobalt_client::HistogramOptions MakeHistogramOptions() {
cobalt_client::HistogramOptions options =
cobalt_client::HistogramOptions::CustomizedExponential(10, 2, 1, 0);
options.metric_id = 1;
options.event_codes = {0, 0, 0, 0, 0};
return options;
}
cobalt_client::MetricOptions MakeCounterOptions() {
cobalt_client::MetricOptions options;
options.metric_id = 1;
options.event_codes = {0, 0, 0, 0, 0};
return options;
}
TEST(CobaltMetricsTest, LogWhileEnabled) {
fs_metrics::Metrics metrics(MakeCollector(), "TestFs");
metrics.EnableMetrics(/*should_collect*/ true);
fs_metrics::FsCommonMetrics* vnodes = metrics.mutable_fs_common_metrics();
ASSERT_NOT_NULL(vnodes);
if (metrics.IsEnabled()) {
vnodes->vnode.close.Add(kLatencyNs);
}
// We should have observed 15 hundred usecs.
EXPECT_EQ(vnodes->vnode.close.GetCount(kLatencyNs), 1);
}
TEST(CobaltMetricsTest, LogWhileNotEnabled) {
fs_metrics::Metrics metrics(MakeCollector(), "TestFs");
metrics.EnableMetrics(/*should_collect*/ false);
fs_metrics::FsCommonMetrics* vnodes = metrics.mutable_fs_common_metrics();
ASSERT_NOT_NULL(vnodes);
if (metrics.IsEnabled()) {
vnodes->vnode.close.Add(kLatencyNs);
}
EXPECT_EQ(vnodes->vnode.close.GetCount(kLatencyNs), 0);
}
TEST(CobaltMetricsTest, EnableMetricsEnabled) {
fs_metrics::Metrics metrics(MakeCollector(), "TestFs");
fs_metrics::FsCommonMetrics* vnodes = metrics.mutable_fs_common_metrics();
ASSERT_NOT_NULL(vnodes);
ASSERT_EQ(vnodes->metrics_enabled, metrics.IsEnabled());
metrics.EnableMetrics(/*should_collect*/ true);
EXPECT_TRUE(metrics.IsEnabled());
EXPECT_TRUE(vnodes->metrics_enabled);
}
TEST(CobaltMetricsTest, EnableMetricsDisabled) {
fs_metrics::Metrics metrics(MakeCollector(), "TestFs");
metrics.EnableMetrics(/*should_collect*/ true);
fs_metrics::FsCommonMetrics* vnodes = metrics.mutable_fs_common_metrics();
ASSERT_NOT_NULL(vnodes);
ASSERT_EQ(vnodes->metrics_enabled, metrics.IsEnabled());
metrics.EnableMetrics(/*should_collect*/ false);
EXPECT_FALSE(metrics.IsEnabled());
EXPECT_FALSE(vnodes->metrics_enabled);
}
TEST(CobaltMetricsTest, AddCustomMetric) {
fs_metrics::Metrics metrics(MakeCollector(), "TestFs");
metrics.EnableMetrics(/*should_collect*/ false);
cobalt_client::Histogram<kBuckets> hist =
cobalt_client::Histogram<kBuckets>(MakeHistogramOptions(), metrics.mutable_collector());
cobalt_client::Counter counter =
cobalt_client::Counter(MakeCounterOptions(), metrics.mutable_collector());
hist.Add(25);
counter.Increment(20);
ASSERT_EQ(hist.GetCount(25), 1);
ASSERT_EQ(counter.GetCount(), 20);
// Sanity check.
metrics.mutable_collector()->Flush();
}
TEST(CobaltMetricsTest, CreateCompressionFormatMetrics) {
cobalt_client::InMemoryLogger* logger;
fs_metrics::Metrics metrics_unknownfs(MakeCollector(&logger), "TestFs");
ASSERT_EQ(metrics_unknownfs.compression_format_metrics().source,
fs_metrics::CompressionSource::kUnknown);
// No compression format counters for an unknown fs.
ASSERT_TRUE(metrics_unknownfs.compression_format_metrics().counters.empty());
fs_metrics::Metrics metrics(MakeCollector(&logger), "blobfs", CompressionSource::kBlobfs);
metrics.EnableMetrics(/*should_collect*/ true);
// Compression format counters created for blobfs.
ASSERT_EQ(metrics.compression_format_metrics().counters.size(),
static_cast<size_t>(fs_metrics::CompressionFormat::kNumFormats));
auto source = fs_metrics::CompressionSource::kBlobfs;
ASSERT_EQ(metrics.compression_format_metrics().source, source);
std::vector<fs_metrics::CompressionFormat> formats = {
fs_metrics::CompressionFormat::kUnknown,
fs_metrics::CompressionFormat::kUncompressed,
fs_metrics::CompressionFormat::kCompressedLZ4,
fs_metrics::CompressionFormat::kCompressedZSTD,
fs_metrics::CompressionFormat::kCompressedZSTDSeekable,
fs_metrics::CompressionFormat::kCompressedZSTDChunked,
};
for (const auto fmt : formats) {
// Counters don't make it to the logger before the collector is Flush()'d.
ASSERT_EQ(logger->counters().find(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
logger->counters().end());
}
ASSERT_TRUE(metrics.mutable_collector()->Flush());
for (const auto fmt : formats) {
// Counters exist after Flush().
ASSERT_NE(logger->counters().find(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
logger->counters().end());
ASSERT_EQ(logger->counters().at(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
0);
}
}
TEST(CobaltMetricsTest, IncrementCompressionFormatMetrics) {
cobalt_client::InMemoryLogger* logger;
fs_metrics::Metrics metrics(MakeCollector(&logger), "blobfs", CompressionSource::kBlobfs);
metrics.EnableMetrics(/*should_collect*/ true);
auto source = fs_metrics::CompressionSource::kBlobfs;
std::vector<fs_metrics::CompressionFormat> formats = {
fs_metrics::CompressionFormat::kUnknown,
fs_metrics::CompressionFormat::kUncompressed,
fs_metrics::CompressionFormat::kCompressedLZ4,
fs_metrics::CompressionFormat::kCompressedZSTD,
fs_metrics::CompressionFormat::kCompressedZSTDSeekable,
fs_metrics::CompressionFormat::kCompressedZSTDChunked,
};
// No counters incremented yet.
for (const auto fmt : formats) {
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt)->GetCount(), 0);
}
ASSERT_TRUE(metrics.mutable_collector()->Flush());
for (const auto fmt : formats) {
// Counters exist after Flush().
ASSERT_NE(logger->counters().find(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
logger->counters().end());
ASSERT_EQ(logger->counters().at(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
0);
}
// Increment counters for a couple of formats.
auto fmt1 = fs_metrics::CompressionFormat::kUncompressed;
auto fmt2 = fs_metrics::CompressionFormat::kCompressedLZ4;
metrics.mutable_compression_format_metrics()->IncrementCounter(fmt1, 10);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt1)->GetCount(), 10);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt2)->GetCount(), 0);
metrics.mutable_compression_format_metrics()->IncrementCounter(fmt2, 20);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt1)->GetCount(), 10);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt2)->GetCount(), 20);
metrics.mutable_compression_format_metrics()->IncrementCounter(fmt1, 10);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt1)->GetCount(), 20);
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt2)->GetCount(), 20);
ASSERT_TRUE(metrics.mutable_collector()->Flush());
// Logger sees the counter increments after Flush().
ASSERT_EQ(logger->counters().at(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt1)),
20);
ASSERT_EQ(logger->counters().at(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt2)),
20);
// No other counters were incremented.
for (const auto fmt : formats) {
if (fmt == fmt1 || fmt == fmt2) {
continue;
}
ASSERT_EQ(logger->counters().at(
fs_metrics::CompressionFormatMetrics::MakeCompressionMetricOptions(source, fmt)),
0);
}
// No pending increments.
for (const auto fmt : formats) {
ASSERT_EQ(metrics.compression_format_metrics().counters.at(fmt)->GetCount(), 0);
}
}
} // namespace
} // namespace fs_metrics