blob: f182061a753d95d6dba358234116cd59e4dc0284 [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 "src/lib/storage/vfs/cpp/metrics/cobalt_metrics.h"
#include <lib/zx/time.h>
#include <lib/zx/vmo.h>
#include <unistd.h>
#include <utility>
#include <vector>
#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 <zxtest/zxtest.h>
namespace fs_metrics {
namespace {
// Observed latency.
constexpr uint32_t kLatencyNs = 5000;
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));
}
TEST(CobaltMetricsTest, LogWhileEnabled) {
fs_metrics::Metrics metrics(MakeCollector(), Source::kUnknown);
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(), Source::kUnknown);
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(), Source::kUnknown);
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(), Source::kUnknown);
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, EventSourceSetInMetricOptions) {
constexpr Source source = Source::kBlobfs;
constexpr uint32_t source_event_code = static_cast<uint32_t>(source);
fs_metrics::Metrics metrics(MakeCollector(), source);
const auto& fs_common_metrics = metrics.fs_common_metrics();
EXPECT_EQ(fs_common_metrics.vnode.close.GetOptions().event_codes[0], source_event_code);
EXPECT_EQ(fs_common_metrics.journal.write_data.GetOptions().event_codes[0], source_event_code);
EXPECT_EQ(fs_common_metrics.fragmentation_metrics.total_nodes.GetOptions().event_codes[0],
source_event_code);
}
TEST(CobaltMetricsTest, CreateCompressionFormatMetrics) {
cobalt_client::InMemoryLogger* logger;
fs_metrics::Metrics metrics_unknownfs(MakeCollector(&logger), Source::kUnknown);
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), Source::kBlobfs, 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.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), Source::kBlobfs, 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.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.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);
}
}
TEST(CobaltMetricsTest, RecordOldestVersionMountedReportsCorrectly) {
cobalt_client::InMemoryLogger* logger;
fs_metrics::Metrics metrics(MakeCollector(&logger), Source::kBlobfs, CompressionSource::kBlobfs);
metrics.RecordOldestVersionMounted("5/5");
EXPECT_TRUE(metrics.Flush());
cobalt_client::MetricOptions expected_options = {
.component = "5/5",
.metric_id = static_cast<uint32_t>(Event::kVersion),
.metric_dimensions = 1,
.event_codes = {static_cast<uint32_t>(Source::kBlobfs)}};
auto iter = logger->counters().find(expected_options);
ASSERT_NE(iter, logger->counters().end());
EXPECT_EQ(iter->second, 1);
}
} // namespace
} // namespace fs_metrics