blob: 7712adfc58082e2ac9f77e9ab2157aeeb529ed6a [file] [log] [blame] [edit]
// 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.
// This file contains information for gathering Blobfs metrics.
#ifndef SRC_STORAGE_BLOBFS_METRICS_H_
#define SRC_STORAGE_BLOBFS_METRICS_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/zx/time.h>
#include <cobalt-client/cpp/collector.h>
#include <fs/journal/journal.h>
#include <fs/metrics/cobalt_metrics.h>
#include <fs/metrics/composite_latency_event.h>
#include <fs/metrics/events.h>
#include <fs/metrics/histograms.h>
#include <fs/ticker.h>
#include <fs/vnode.h>
#include "src/storage/blobfs/format.h"
#include "src/storage/blobfs/read-metrics.h"
#include "src/storage/blobfs/verification-metrics.h"
namespace blobfs {
// Alias for the LatencyEvent used in blobfs.
using LatencyEvent = fs_metrics::CompositeLatencyEvent;
// This struct holds the inspect node for a blob and a map from block index to page-in frequency.
struct BlobPageInFrequencies {
inspect::Node blob_root_node;
std::map<uint32_t, inspect::UintProperty> offset_map;
};
// This class is not thread-safe except for the read_metrics() and verification_metrics() accessors.
class BlobfsMetrics : public fs::MetricsTrait {
public:
explicit BlobfsMetrics(bool should_record_page_in = false);
~BlobfsMetrics();
// Print information about metrics to stdout.
//
// TODO(fxbug.dev/31862): This is a stop-gap solution; long-term, this information
// should be extracted from devices.
void Dump();
// Begin collecting blobfs metrics. Metrics collection is not implicitly enabled
// with the creation of a "BlobfsMetrics" object.
void Collect();
bool Collecting() const { return cobalt_metrics_.IsEnabled(); }
// Updates aggregate information about the total number of created
// blobs since mounting.
void UpdateAllocation(uint64_t size_data, const fs::Duration& duration);
// Updates aggregate information about the number of blobs opened
// since mounting.
void UpdateLookup(uint64_t size);
// Updates aggregates information about blobs being written back
// to blobfs since mounting.
void UpdateClientWrite(uint64_t data_size, uint64_t merkle_size,
const fs::Duration& enqueue_duration,
const fs::Duration& generate_duration);
// Returns a new Latency event for the given event. This requires the event to be backed up by
// an histogram in both cobalt metrics and Inspect.
fs_metrics::CompositeLatencyEvent NewLatencyEvent(fs_metrics::Event event) final {
return LatencyEvent(event, &histograms_, cobalt_metrics_.mutable_fs_common_metrics());
}
inspect::Node* GetInspectRoot() override { return &journal_stats_; }
// Increments Cobalt metrics tracking compression formats. Extracts the compression format from
// the |inode| header, and increments the counter for that format with the inode's |blob_size|.
void IncrementCompressionFormatMetric(const Inode& inode);
// Increments a read of Merkle Tree data from disk.
// This method must only be called from the blobfs main thread.
void IncrementMerkleDiskRead(uint64_t read_size, fs::Duration read_duration);
// Increments the frequency count for blocks in the range [|offset|, |offset| + |length|).
// This method must only be called from the pager thread.
// NOTE: This method is a NOP unless |BLOBFS_ENABLE_PAGE_IN_METRICS| compiler flag
// has been set in the BUILD.gn
void IncrementPageIn(const fbl::String& merkle_hash, uint64_t offset, uint64_t length);
// Accessors for ReadMetrics. The metrics objects returned are NOT thread-safe.
// The metrics objects are to be used by exactly one thread (main or pager).
// Used to increment relevant metrics from the blobfs main thread and the user pager thread.
ReadMetrics& paged_read_metrics() { return paged_read_metrics_; }
ReadMetrics& unpaged_read_metrics() { return unpaged_read_metrics_; }
// Accessor for VerificationMetrics. This metrics object is thread-safe.
// Used to increment relevant metrics from the blobfs main thread and the user pager thread.
// The |BlobfsMetrics| class is not thread-safe except for this accessor.
VerificationMetrics& verification_metrics() { return verification_metrics_; }
// Accessor for BlobFS Inspector. This Inspector serves the BlobFS inspect tree.
inspect::Inspector* inspector() { return &inspector_; }
fs_metrics::Metrics& cobalt_metrics() { return cobalt_metrics_; }
private:
// Flushes the metrics to the cobalt client and schedules itself to flush again.
void ScheduleMetricFlush();
static inspect::Inspector CreateInspector();
// Inspect instrumentation data.
inspect::Inspector inspector_ = CreateInspector();
inspect::Node& root_ = inspector_.GetRoot();
// ALLOCATION STATS
// Created with external-facing "Create".
uint64_t blobs_created_ = 0;
// Measured by space allocated with "Truncate".
uint64_t blobs_created_total_size_ = 0;
zx::ticks total_allocation_time_ticks_ = {};
// WRITEBACK STATS
// Measurements, from the client's perspective, of writing and enqueing
// data that will later be written to disk.
uint64_t data_bytes_written_ = 0;
uint64_t merkle_bytes_written_ = 0;
zx::ticks total_write_enqueue_time_ticks_ = {};
zx::ticks total_merkle_generation_time_ticks_ = {};
// LOOKUP STATS
// Opened via "LookupBlob".
uint64_t blobs_opened_ = 0;
uint64_t blobs_opened_total_size_ = 0;
// INSPECT NODES AND PROPERTIES
inspect::Node allocation_stats_ = root_.CreateChild("allocation_stats");
inspect::Node writeback_stats_ = root_.CreateChild("writeback_stats");
inspect::Node lookup_stats_ = root_.CreateChild("lookup_stats");
inspect::Node paged_read_stats_ = root_.CreateChild("paged_read_stats");
inspect::Node unpaged_read_stats_ = root_.CreateChild("unpaged_read_stats");
inspect::Node page_in_frequency_stats_ = root_.CreateChild("page_in_frequency_stats");
inspect::Node journal_stats_ = root_.CreateChild("journal_stats");
// Allocation properties
inspect::UintProperty blobs_created_property_ =
allocation_stats_.CreateUint("blobs_created", blobs_created_);
inspect::UintProperty blobs_created_total_size_property_ =
allocation_stats_.CreateUint("blobs_created_total_size", blobs_created_total_size_);
inspect::IntProperty total_allocation_time_ticks_property_ = allocation_stats_.CreateInt(
"total_allocation_time_ticks", total_allocation_time_ticks_.get());
// Writeback properties
inspect::UintProperty data_bytes_written_property_ =
writeback_stats_.CreateUint("data_bytes_written", data_bytes_written_);
inspect::UintProperty merkle_bytes_written_property_ =
writeback_stats_.CreateUint("merkle_bytes_written", merkle_bytes_written_);
inspect::IntProperty total_write_enqueue_time_ticks_property_ = writeback_stats_.CreateInt(
"total_write_enqueue_time_ticks", total_write_enqueue_time_ticks_.get());
inspect::IntProperty total_merkle_generation_time_ticks_property_ = writeback_stats_.CreateInt(
"total_merkle_generation_time_ticks", total_merkle_generation_time_ticks_.get());
// Lookup properties
inspect::UintProperty blobs_opened_property_ =
lookup_stats_.CreateUint("blobs_opened", blobs_opened_);
inspect::UintProperty blobs_opened_total_size_property_ =
lookup_stats_.CreateUint("blobs_opened_total_size", blobs_opened_total_size_);
// READ STATS
ReadMetrics paged_read_metrics_{&paged_read_stats_};
ReadMetrics unpaged_read_metrics_{&unpaged_read_stats_};
zx::ticks total_read_merkle_time_ticks_ = {};
uint64_t bytes_merkle_read_from_disk_ = 0;
// PAGE-IN FREQUENCY STATS
bool should_record_page_in = false;
std::map<fbl::String, BlobPageInFrequencies> all_page_in_frequencies_;
// VERIFICATION STATS
VerificationMetrics verification_metrics_;
// FVM STATS
// TODO(smklein)
fs_metrics::Histograms histograms_ = fs_metrics::Histograms(&root_);
// Cobalt metrics.
fs_metrics::Metrics cobalt_metrics_ =
fs_metrics::Metrics(std::make_unique<cobalt_client::Collector>(fs_metrics::kCobaltProjectId),
fs_metrics::Component::kBlobfs, fs_metrics::CompressionSource::kBlobfs);
// Loop for flushing the collector periodically.
async::Loop flush_loop_ = async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread);
};
} // namespace blobfs
#endif // SRC_STORAGE_BLOBFS_METRICS_H_