NVMeSubsystem: instantiate the scheduler for Metric Instantiate the scheduler for each subsystem to schedule the Metrics cache refresh. The life time of scheduler is between [Intiatilzing, Terminating) of attached subsystem. The scheduler is started as the last step of the Intiatilzing and right before the Start status. Check the design doc: go/nvme-mi-cache-time-scheduling#heading=h.f584d1vzjwgg Google-Bug-Id: 348660385 Tested: 348660385#comment3 (with all changes from go/gbmcl-ext/q/topic:%22nvme+cache%22) Signed-off-by: Hao Jiang <jianghao@google.com> Change-Id: Ie0f663e23430698abcca3451bceaeeec2be72360
diff --git a/src/NVMeCache.hpp b/src/NVMeCache.hpp index 09afbdc..e0dce89 100644 --- a/src/NVMeCache.hpp +++ b/src/NVMeCache.hpp
@@ -106,6 +106,11 @@ explicit Scheduler(boost::asio::io_context& io); ~Scheduler() = default; + // find the schuduler with give path for a storage componenet (e.g. + // Controller) + static std::shared_ptr<Scheduler<ClockType_>> + getScheduler(const std::string& path); + void enqueue(std::chrono::time_point<ClockType> scheduledTime, std::shared_ptr<MetricBase<ClockType>> task); void dequeue();
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp index 4932970..fa460e7 100644 --- a/src/NVMeController.cpp +++ b/src/NVMeController.cpp
@@ -19,6 +19,7 @@ // using sdbusplus::xyz::openbmc_project::Inventory::Item::server:: // StorageController; using sdbusplus::xyz::openbmc_project::NVMe::server::NVMeAdmin; +using SchedulerClockType = std::chrono::steady_clock; std::shared_ptr<NVMeControllerEnabled> NVMeControllerEnabled::create(NVMeController&& nvmeController) @@ -180,11 +181,14 @@ this->metricStore.emplace(this->NVMeController::io, this->NVMeController::conn, this->NVMeController::path); + + auto scheduler = Scheduler<SchedulerClockType>::getScheduler(path); + // NOLINTBEGIN(performance-unnecessary-value-param) auto completeCB = - [weakCntrl{weak_from_this()}, path{path}]( - std::string_view name, - std::shared_ptr<MetricBase<std::chrono::steady_clock>> metric) { + [weakCntrl{weak_from_this()}, + path{path}](std::string_view name, + std::shared_ptr<MetricBase<SchedulerClockType>> metric) { auto cntrl = weakCntrl.lock(); if (!cntrl || !cntrl->metricStore) { @@ -218,13 +222,13 @@ // NOLINTEND(performance-unnecessary-value-param) using SMARTMetric = - ControllerLogPageMetric<NVME_LOG_LID_SMART, std::chrono::steady_clock>; + ControllerLogPageMetric<NVME_LOG_LID_SMART, SchedulerClockType>; // NOLINTBEGIN(modernize-make-shared) auto smart = std::shared_ptr<SMARTMetric>(new SMARTMetric( - this->weak_from_this(), {}, + this->weak_from_this(), scheduler, // TODO: configurable interval - std::chrono::duration_cast<std::chrono::steady_clock::duration>( + std::chrono::duration_cast<SchedulerClockType::duration>( std::chrono::seconds(60)), std::bind_front(completeCB, SMARTMetric::logpageIdentifier()))); // NOLINTEND(modernize-make-shared)
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp index bf6f31e..accdd1a 100644 --- a/src/NVMeSubsys.cpp +++ b/src/NVMeSubsys.cpp
@@ -1,6 +1,7 @@ #include "NVMeSubsys.hpp" #include "AsioHelper.hpp" +#include "NVMeCache.hpp" #include "NVMeDrive.hpp" #include "NVMeError.hpp" #include "NVMePlugin.hpp" @@ -12,9 +13,53 @@ #include <boost/asio/spawn.hpp> +#include <algorithm> #include <charconv> #include <filesystem> #include <stdexcept> +#include <unordered_map> + +using SchedulerClockType = std::chrono::steady_clock; +std::unordered_map<std::string, std::shared_ptr<Scheduler<SchedulerClockType>>> + schedulers; + +template <> +std::shared_ptr<Scheduler<SchedulerClockType>> + Scheduler<SchedulerClockType>::getScheduler(const std::string& path) +{ + auto itr = std::find_if( + schedulers.begin(), schedulers.end(), + [&path](const std::pair<std::string, + std::shared_ptr<Scheduler<SchedulerClockType>>>& + pair) { + // check if the given path is subdir of the subsystem path + const std::string& parent = pair.first; + if (parent.empty() || path.empty()) + { + return false; + } + if (parent.size() > path.size()) + { + return false; + } + if (!path.starts_with(parent)) + { + return false; + } + if (parent.back() != '/' && path.size() > parent.size() && + path.at(parent.size()) != '/') + { + return false; + } + + return true; + }); + if (itr == schedulers.end()) + { + return {}; + } + return itr->second; +} void NVMeSubsystem::createAssociation() { @@ -216,6 +261,15 @@ self->plugin->start(); } + // start Metric Scheduler + auto scheduler = + Scheduler<SchedulerClockType>::getScheduler(self->path); + assert( + scheduler && + "scheduler should be created at the beginning of Initializing Status"); + scheduler->start(); + scheduler->dequeue(); + self->status = Status::Start; }); } @@ -249,6 +303,10 @@ assert(status == Status::Start || status == Status::Aborting); status = Status::Terminating; + + // erase the scheduler to stop furthur Metric scheduling + schedulers.erase(path); + if (plugin) { plugin->stop(); @@ -334,6 +392,12 @@ assert(status == Status::Stop); status = Status::Intiatilzing; + + // create scheduler + assert(schedulers.find(path) == schedulers.end() && + "scheduler should exsit only between [Intiatilzing, Terminating)"); + schedulers.emplace(path, new Scheduler<SchedulerClockType>(io)); + markAvailable(toggle); // add controllers for the subsystem