Commit 328fc7ff authored by Roman Aleksandrov's avatar Roman Aleksandrov Committed by Commit Bot

VersionUpdater: Add new update progress calculation.

Add new update progress calculation which is based on total time left
expectation. New update progress is gradually changed during the update.

Bug: 1117036
Change-Id: I11478e06af64137ebc7643495d198537d1031657
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2358681Reviewed-by: default avatarRoman Sorokin [CET] <rsorokin@chromium.org>
Commit-Queue: Roman Aleksandrov <raleksandrov@google.com>
Cr-Commit-Position: refs/heads/master@{#799621}
parent e4b5cae2
......@@ -18,16 +18,25 @@ constexpr base::TimeDelta kDownloadTime = base::TimeDelta::FromMinutes(50);
constexpr base::TimeDelta kVerifyingTime = base::TimeDelta::FromMinutes(5);
constexpr base::TimeDelta kFinalizingTime = base::TimeDelta::FromMinutes(5);
struct StageTimeExpectation {
// Progress in percent falls on a stage. Should be 100 in total.
const int kDownloadProgress = 90;
const int kVerifyingProgress = 5;
const int kFinalizingProgress = 5;
const int kTotalProgress = 100;
struct StageTimeExpectationProgress {
update_engine::Operation stage_;
base::TimeDelta time_estimation_;
int progress_;
};
// Stages for which |estimated_time_left| should be calculated.
constexpr StageTimeExpectation kStages[] = {
{update_engine::Operation::DOWNLOADING, kDownloadTime},
{update_engine::Operation::VERIFYING, kVerifyingTime},
{update_engine::Operation::FINALIZING, kFinalizingTime},
// Stages for which `estimated_time_left` and progress should be calculated.
constexpr StageTimeExpectationProgress kStages[] = {
{update_engine::Operation::DOWNLOADING, kDownloadTime, kDownloadProgress},
{update_engine::Operation::VERIFYING, kVerifyingTime, kVerifyingProgress},
{update_engine::Operation::FINALIZING, kFinalizingTime,
kFinalizingProgress},
};
// Minimum timestep between two consecutive measurements for the download rates.
......@@ -74,12 +83,14 @@ base::TimeDelta UpdateTimeEstimator::GetDownloadTimeLeft() const {
return download_time_left_;
}
base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const {
UpdateTimeEstimator::UpdateStatus UpdateTimeEstimator::GetUpdateStatus() const {
base::TimeDelta time_left_estimation;
int progress_left = 0;
bool stage_found = false;
for (const auto& el : kStages) {
if (stage_found) {
time_left_estimation += el.time_estimation_;
progress_left += el.progress_;
}
if (el.stage_ != current_stage_)
continue;
......@@ -90,6 +101,7 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const {
tick_clock_->NowTicks() - stage_started_time_;
const base::TimeDelta time_left =
std::max(el.time_estimation_ - time_spent, base::TimeDelta());
// Time left calculation.
if (current_stage_ == update_engine::Operation::DOWNLOADING &&
has_download_time_estimation_) {
const base::TimeDelta time_left_speed_estimation =
......@@ -98,8 +110,18 @@ base::TimeDelta UpdateTimeEstimator::GetTimeLeft() const {
} else {
time_left_estimation += time_left;
}
// Progress left calculation.
if (current_stage_ == update_engine::Operation::DOWNLOADING) {
const double download_progress_left = 1.0 - download_last_progress_;
const int current_stage_progress_left =
base::ClampRound(download_progress_left * el.progress_);
progress_left += current_stage_progress_left;
} else {
progress_left +=
base::ClampRound((time_left / el.time_estimation_) * el.progress_);
}
}
return time_left_estimation;
return {time_left_estimation, kTotalProgress - progress_left};
}
void UpdateTimeEstimator::UpdateForTotalTimeLeftEstimation(
......
......@@ -17,6 +17,10 @@ namespace chromeos {
// Helper class that gives time left expectations.
class UpdateTimeEstimator {
public:
struct UpdateStatus {
base::TimeDelta time_left;
int progress;
};
UpdateTimeEstimator();
// Updates data needed for estimation.
......@@ -29,8 +33,9 @@ class UpdateTimeEstimator {
// Estimate time left for a downloading stage to complete.
base::TimeDelta GetDownloadTimeLeft() const;
// Estimate time left for an update to complete.
base::TimeDelta GetTimeLeft() const;
// Estimate time left for an update to complete and current update progress in
// procents.
UpdateStatus GetUpdateStatus() const;
void set_tick_clock_for_testing(const base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
......
......@@ -13,6 +13,8 @@ constexpr int kFinalizingTimeInSeconds = 5 * 60;
constexpr base::TimeDelta kTimeAdvanceSeconds10 =
base::TimeDelta::FromSeconds(10);
constexpr base::TimeDelta kTimeAdvanceSeconds60 =
base::TimeDelta::FromSeconds(60);
constexpr base::TimeDelta kZeroTime = base::TimeDelta();
} // anonymous namespace
......@@ -67,12 +69,41 @@ TEST_F(UpdateTimeEstimatorUnitTest, TotalTimeLeft) {
time_estimator_.Update(status);
tick_clock_.Advance(kTimeAdvanceSeconds10);
EXPECT_EQ(time_estimator_.GetTimeLeft(),
EXPECT_EQ(time_estimator_.GetUpdateStatus().time_left,
base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds) -
kTimeAdvanceSeconds10);
tick_clock_.Advance(base::TimeDelta::FromSeconds(kFinalizingTimeInSeconds));
EXPECT_EQ(time_estimator_.GetTimeLeft(), kZeroTime);
EXPECT_EQ(time_estimator_.GetUpdateStatus().time_left, kZeroTime);
}
TEST_F(UpdateTimeEstimatorUnitTest, DownloadingProgress) {
update_engine::StatusResult status =
CreateStatusResult(update_engine::Operation::DOWNLOADING, 1.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 0);
tick_clock_.Advance(kTimeAdvanceSeconds10);
status.set_progress(0.01);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 1);
tick_clock_.Advance(kTimeAdvanceSeconds10);
status.set_progress(0.10);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 9);
status = CreateStatusResult(update_engine::Operation::VERIFYING, 0.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 90);
tick_clock_.Advance(kTimeAdvanceSeconds60);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 91);
status = CreateStatusResult(update_engine::Operation::FINALIZING, 0.0, 0.0);
time_estimator_.Update(status);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 95);
tick_clock_.Advance(kTimeAdvanceSeconds60);
EXPECT_EQ(time_estimator_.GetUpdateStatus().progress, 96);
}
} // namespace chromeos
......@@ -253,7 +253,9 @@ void VersionUpdater::UpdateStatusChanged(
}
if (time_estimator_.HasTotalTime(status.current_operation())) {
update_info_.total_time_left = time_estimator_.GetTimeLeft();
const auto update_status = time_estimator_.GetUpdateStatus();
update_info_.total_time_left = update_status.time_left;
update_info_.better_update_progress = update_status.progress;
if (!refresh_timer_) {
refresh_timer_ = std::make_unique<base::RepeatingTimer>(tick_clock_);
refresh_timer_->Start(FROM_HERE, kUpdateTime, this,
......@@ -272,7 +274,9 @@ void VersionUpdater::UpdateStatusChanged(
}
void VersionUpdater::RefreshTimeLeftEstimation() {
update_info_.total_time_left = time_estimator_.GetTimeLeft();
const auto update_status = time_estimator_.GetUpdateStatus();
update_info_.total_time_left = update_status.time_left;
update_info_.better_update_progress = update_status.progress;
delegate_->UpdateInfoChanged(update_info_);
}
......
......@@ -52,6 +52,8 @@ class VersionUpdater : public UpdateEngineClient::Observer,
// Time left for an update to finish in seconds.
base::TimeDelta total_time_left;
// Progress of an update which is based on total time left expectation.
int better_update_progress = 0;
// Estimated time left for only downloading stage, in seconds.
// TODO(crbug.com/1101317): Remove when better update is launched.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment