| #include "boot_manager.hpp" |
| |
| #include "utils.hpp" |
| |
| #include <fmt/printf.h> |
| |
| #include <string_view> |
| #include <vector> |
| |
| namespace boot_time_monitor |
| { |
| |
| namespace |
| { |
| constexpr uint32_t kMaxCheckpointCnt = 100; |
| constexpr uint32_t kMaxDurationCnt = 100; |
| } // namespace |
| |
| /** |
| * BootManager implementation class |
| */ |
| BootManager::BootManager(std::shared_ptr<UtilIface> util, |
| const std::shared_ptr<FileUtilIface>& cpCSV, |
| const std::shared_ptr<FileUtilIface>& durCSV) : |
| util(std::move(util)), cpCSV(cpCSV), durCSV(durCSV) |
| { |
| checkpoints = std::move(*cpCSV->loadCheckpoints(false)); |
| durations = std::move(*durCSV->loadDurations(false)); |
| preCheckpoints = std::move(*cpCSV->loadCheckpoints(true)); |
| preDurations = std::move(*durCSV->loadDurations(true)); |
| } |
| |
| void BootManager::setCheckpoint(std::string_view cpName, |
| int64_t externalWallTime, int64_t duration) |
| { |
| auto wallTime = externalWallTime == 0 ? util->getWallTimeInMs() |
| : externalWallTime; |
| auto upTime = util->getUpTimeInMs(); |
| if (upTime == std::nullopt) |
| { |
| fmt::print("[{}] Can't get up time. Skip this checkpoint.\n", |
| __FUNCTION__); |
| return; |
| } |
| if (!util->isValidName(cpName)) |
| { |
| fmt::print( |
| "[{}] Name is invalid. Only allows [0-9a-zA-Z_:] but get: {}\n", |
| __FUNCTION__, cpName); |
| return; |
| } |
| |
| if (checkpoints.size() >= kMaxCheckpointCnt) |
| { |
| fmt::print("[{}] Drop incoming checkpoint due to hit the limit. " |
| "name={}, externalWallTime={}, duration={}\n", |
| __FUNCTION__, cpName, externalWallTime, duration); |
| return; |
| } |
| // `boot_manager` helps to calculate the transition time from one stage to |
| // next stage if the user can provide a self measured duration for the |
| // current stage. |
| // For example, if the interval between checkpoint A and B is 10 seconds and |
| // the user knows B stage only uses 8 seconds to boot up. Then that means 2 |
| // seconds transition time was cost from A stage to B stage. |
| // `duration == 0` means "I don't have self measured duration, so no need to |
| // calculate transition time for me". |
| if (duration != 0) |
| { |
| checkpoints.emplace_back(cpName.data() + std::string{kBeginStageSuffix}, |
| wallTime - duration, |
| upTime.value() - duration); |
| cpCSV->addCheckpoint(checkpoints.back().name, |
| checkpoints.back().wallTime, |
| checkpoints.back().monoTime); |
| |
| if (checkpoints.size() >= kMaxCheckpointCnt) |
| { |
| fmt::print( |
| "[{}] Incoming checkpoint has `duration` so `To_{}` has been " |
| "created and added. Since the size is full so the incoming " |
| "checkpoint has been dropped\n", |
| __FUNCTION__, cpName); |
| return; |
| } |
| } |
| |
| checkpoints.emplace_back(std::string{cpName}, wallTime, upTime.value()); |
| cpCSV->addCheckpoint(checkpoints.back().name, checkpoints.back().wallTime, |
| checkpoints.back().monoTime); |
| } |
| |
| void BootManager::setDuration(std::string_view durName, int64_t duration) |
| { |
| if (!util->isValidName(durName)) |
| { |
| fmt::print( |
| "[{}] Name is invalid. Only allows [0-9a-zA-Z_:] but get: {}\n", |
| __FUNCTION__, durName); |
| return; |
| } |
| |
| if (durations.size() >= kMaxDurationCnt) |
| { |
| fmt::print("[{}] Drop incoming duration due to hit the limit. " |
| "name={}, duration={}\n", |
| __FUNCTION__, durName, duration); |
| return; |
| } |
| |
| durations.emplace_back(std::string(durName), duration); |
| durCSV->addDuration(durations.back().name, durations.back().duration); |
| } |
| |
| void BootManager::notifyComplete() |
| { |
| std::swap(preCheckpoints, checkpoints); |
| checkpoints.clear(); |
| std::swap(preDurations, durations); |
| durations.clear(); |
| |
| cpCSV->completeCurrent(); |
| durCSV->completeCurrent(); |
| } |
| |
| bool BootManager::isRebooting() |
| { |
| return !(cpCSV->isEmpty() && durCSV->isEmpty()); |
| } |
| |
| const std::vector<Checkpoint>& BootManager::getCheckpoints() const |
| { |
| return checkpoints; |
| } |
| |
| const std::vector<Duration>& BootManager::getDurations() const |
| { |
| return durations; |
| } |
| |
| const std::vector<Checkpoint>& BootManager::getPreCheckpoints() const |
| { |
| return preCheckpoints; |
| } |
| |
| const std::vector<Duration>& BootManager::getPreDurations() const |
| { |
| return preDurations; |
| } |
| |
| } // namespace boot_time_monitor |