blob: 4a726b5eed4a8c4a79e224b42b5c38e3f61e13f2 [file] [log] [blame]
#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