update_engine: Reduce prefs writes during update

Currently we checkpoint after every operation during an update in order
to allow us to resume if an update is interrupted for some reason. In
addition, we write the current uptime duration every time we receive
data over the network in order to collect total uptime metrics when an
update finishes, even if it was interrupted by a restart. In practice,
this results in a massive number of writes to prefs files during an
update (~70000 calls to creat on the samus build I tested).

This change introduces rate limiting to both of these mechanisms, such
that checkpoints and changes in uptime are persisted at most once per
second. This reduces the number of calls to creat to around 650.

BUG=chromium:898648
TEST=Perform an update while running strace:
strace -p <pidof update_engine> -f -e '!read,write,sendto,recvfrom'

Change-Id: Icadc8de4efdebf480ef37c6ef69603e250212102
Reviewed-on: https://chromium-review.googlesource.com/1316467
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/payload_state.cc b/payload_state.cc
index 4670b14..72144ef 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -55,6 +55,9 @@
 // We want to randomize retry attempts after the backoff by +/- 6 hours.
 static const uint32_t kMaxBackoffFuzzMinutes = 12 * 60;
 
+// Limit persisting current update duration uptime to once per second
+static const uint64_t kUptimeResolution = 1;
+
 PayloadState::PayloadState()
     : prefs_(nullptr),
       using_p2p_for_downloading_(false),
@@ -1151,9 +1154,12 @@
 void PayloadState::CalculateUpdateDurationUptime() {
   Time now = system_state_->clock()->GetMonotonicTime();
   TimeDelta uptime_since_last_update = now - update_duration_uptime_timestamp_;
-  TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update;
-  // We're frequently called so avoid logging this write
-  SetUpdateDurationUptimeExtended(new_uptime, now, false);
+
+  if (uptime_since_last_update > TimeDelta::FromSeconds(kUptimeResolution)) {
+    TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update;
+    // We're frequently called so avoid logging this write
+    SetUpdateDurationUptimeExtended(new_uptime, now, false);
+  }
 }
 
 string PayloadState::GetPrefsKey(const string& prefix, DownloadSource source) {