blob: 47d3204cc30ecb2d5c78061488c7b64a663c0782 [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.
#ifndef SRC_LIB_STORAGE_VFS_CPP_METRICS_COBALT_METRICS_H_
#define SRC_LIB_STORAGE_VFS_CPP_METRICS_COBALT_METRICS_H_
#include <cstdint>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <utility>
#include <cobalt-client/cpp/collector.h>
#include <cobalt-client/cpp/counter.h>
#include <cobalt-client/cpp/histogram.h>
#include <cobalt-client/cpp/integer.h>
#include <fbl/string.h>
#include "cobalt-client/cpp/integer.h"
#include "src/lib/fxl/synchronization/thread_annotations.h"
#include "src/lib/storage/vfs/cpp/metrics/events.h"
namespace fs_metrics {
// local_storage project ID as defined in cobalt-analytics projects.yaml.
static constexpr uint32_t kCobaltProjectId = 3676913920;
using CompressionFormatCounter =
std::unordered_map<fs_metrics::CompressionFormat, std::unique_ptr<cobalt_client::Counter>>;
// Fs related histograms.
struct FsCommonMetrics {
// Number of buckets used for the these metrics.
static constexpr uint32_t kHistogramBuckets = 10;
FsCommonMetrics(cobalt_client::Collector* collector, Source source);
struct VnodeMetrics {
cobalt_client::Histogram<kHistogramBuckets> close;
cobalt_client::Histogram<kHistogramBuckets> read;
cobalt_client::Histogram<kHistogramBuckets> write;
cobalt_client::Histogram<kHistogramBuckets> append;
cobalt_client::Histogram<kHistogramBuckets> truncate;
cobalt_client::Histogram<kHistogramBuckets> set_attr;
cobalt_client::Histogram<kHistogramBuckets> get_attr;
cobalt_client::Histogram<kHistogramBuckets> sync;
cobalt_client::Histogram<kHistogramBuckets> read_dir;
cobalt_client::Histogram<kHistogramBuckets> look_up;
cobalt_client::Histogram<kHistogramBuckets> create;
cobalt_client::Histogram<kHistogramBuckets> unlink;
cobalt_client::Histogram<kHistogramBuckets> link;
} vnode;
struct JournalMetrics {
cobalt_client::Histogram<kHistogramBuckets> write_data;
cobalt_client::Histogram<kHistogramBuckets> write_metadata;
cobalt_client::Histogram<kHistogramBuckets> trim_data;
cobalt_client::Histogram<kHistogramBuckets> sync;
cobalt_client::Histogram<kHistogramBuckets> schedule_task;
cobalt_client::Histogram<kHistogramBuckets> writer_write_data;
cobalt_client::Histogram<kHistogramBuckets> writer_write_metadata;
cobalt_client::Histogram<kHistogramBuckets> writer_trim_data;
cobalt_client::Histogram<kHistogramBuckets> writer_sync;
cobalt_client::Histogram<kHistogramBuckets> writer_write_info_block;
} journal;
struct FragmentationMetrics {
// Total number of nodes in the system. These nodes can be used for inodes or for extent
// containers(in case of blobfs).
cobalt_client::Integer total_nodes;
// Total number of nodes used as inodes for blobs or for files/directories.
cobalt_client::Integer inodes_in_use;
// Total number of nodes used as extent containers.
cobalt_client::Integer extent_containers_in_use;
// Stats about number of extents used per blob. This shows per blob fragmentation of used data
// blocks. It gives us an idea about fragmentation from blob to blob - some blobs might be more
// fragmented than the others.
cobalt_client::Histogram<kHistogramBuckets> extents_per_file;
// Stats about used data blocks fragments. This shows used block fragmentation within
// the filesystem.
cobalt_client::Histogram<kHistogramBuckets> in_use_fragments;
// Stats about free data blocks fragments. This provides an important insight into
// success/failure
// of OTA.
cobalt_client::Histogram<kHistogramBuckets> free_fragments;
} fragmentation_metrics;
// Mirrors |Metrics::IsEnabled|, such that |FsCommonMetrics| is self sufficient
// to determine whether metrics should be logged or not.
bool metrics_enabled = false;
};
// Tracks distribution across the various compression formats supported by a filesystem. Keeps a
// counter of total file sizes (in bytes) for each format type.
//
// Currently used by blobfs. The sizes tracked are uncompressed sizes (the inode's blob_size) for a
// fair comparison between the different compressed and uncompressed formats.
struct CompressionFormatMetrics {
CompressionFormatMetrics(cobalt_client::Collector* collector,
fs_metrics::CompressionSource compression_source);
// Increments the counter for |format| by |size|.
void IncrementCounter(fs_metrics::CompressionFormat format, uint64_t size);
// For testing.
static cobalt_client::MetricOptions MakeCompressionMetricOptions(
fs_metrics::CompressionSource source, fs_metrics::CompressionFormat format);
// Maps compression format to |cobalt_client::Counter|.
CompressionFormatCounter counters;
// Filesystem source the metrics are associated with.
fs_metrics::CompressionSource source = fs_metrics::CompressionSource::kUnknown;
};
// Provides a base class for collecting metrics in FS implementations. This is optional, but
// provides a source of truth of how data is collected for filesystems. Specific filesystem
// implementations with custom APIs can extend and collect more data, but for basic operations, this
// class provides the base infrastructure.
//
// TODO(gevalentino): Define the |event_code| per metric. Currently is ignored.
class Metrics {
public:
Metrics() = delete;
Metrics(std::unique_ptr<cobalt_client::Collector> collector, Source source,
CompressionSource compression_source = CompressionSource::kUnknown);
Metrics(const Metrics&) = delete;
Metrics(Metrics&&) = delete;
Metrics& operator=(const Metrics&) = delete;
Metrics& operator=(Metrics&&) = delete;
virtual ~Metrics() = default;
// Sets metric collection status to |should_collect|.
void EnableMetrics(bool should_enable);
// Returns true if the Logger is collecting.
bool IsEnabled() const;
// Flushes all metrics. Returns true if successful.
bool Flush();
const FsCommonMetrics& fs_common_metrics() const;
FsCommonMetrics* mutable_fs_common_metrics();
const CompressionFormatMetrics& compression_format_metrics() const;
CompressionFormatMetrics* mutable_compression_format_metrics();
void RecordOldestVersionMounted(std::string_view version);
FsCommonMetrics::FragmentationMetrics& FragmentationMetrics() {
return fs_common_metrics_.fragmentation_metrics;
}
private:
struct CompareCounters {
using is_transparent = cobalt_client::MetricOptions;
bool operator()(const std::unique_ptr<cobalt_client::Counter>& left,
const std::unique_ptr<cobalt_client::Counter>& right) const {
return cobalt_client::MetricOptions::LessThan()(left->GetOptions(), right->GetOptions());
}
bool operator()(const std::unique_ptr<cobalt_client::Counter>& left,
const cobalt_client::MetricOptions& right) const {
return cobalt_client::MetricOptions::LessThan()(left->GetOptions(), right);
}
bool operator()(const cobalt_client::MetricOptions& left,
const std::unique_ptr<cobalt_client::Counter>& right) const {
return cobalt_client::MetricOptions::LessThan()(left, right->GetOptions());
}
};
std::mutex mutex_;
Source source_;
std::unique_ptr<cobalt_client::Collector> collector_ FXL_GUARDED_BY(mutex_);
FsCommonMetrics fs_common_metrics_;
CompressionFormatMetrics compression_format_metrics_;
// Low frequency counters created on the fly with dynamic metric options. Currently used
// just for recording the oldest versions and discarded after flushing.
std::set<std::unique_ptr<cobalt_client::Counter>, CompareCounters> temporary_counters_
FXL_GUARDED_BY(mutex_);
bool is_enabled_ = false;
};
} // namespace fs_metrics
#endif // SRC_LIB_STORAGE_VFS_CPP_METRICS_COBALT_METRICS_H_