diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index 17a0858..e66118f6 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -287,7 +287,6 @@
     <classpathentry kind="lib" path="out/Debug/lib.java/sync/android/sync_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/sync/test_support_proto_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_data_chart/android_data_chart_java.jar"/>
-    <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_media/android_media_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_protobuf/protobuf_nano_javalib.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/third_party/android_swipe_refresh/android_swipe_refresh_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/third_party/cacheinvalidation/cacheinvalidation_javalib.jar"/>
diff --git a/tools/android/forwarder2/BUILD.gn b/tools/android/forwarder2/BUILD.gn
index 9a28729..b674344 100644
--- a/tools/android/forwarder2/BUILD.gn
+++ b/tools/android/forwarder2/BUILD.gn
@@ -43,7 +43,7 @@
     ]
     deps = [
       "//base",
-      "//build/config/sanitizers:deps",
+      "//build/config:exe_and_shlib_deps",
       "//tools/android/common",
     ]
     data_deps = [
@@ -86,7 +86,7 @@
     ]
     deps = [
       "//base",
-      "//build/config/sanitizers:deps",
+      "//build/config:exe_and_shlib_deps",
       "//tools/android/common",
     ]
   }
diff --git a/tools/android/forwarder2/device_controller.cc b/tools/android/forwarder2/device_controller.cc
index 7236baf9..5c018d9c 100644
--- a/tools/android/forwarder2/device_controller.cc
+++ b/tools/android/forwarder2/device_controller.cc
@@ -37,7 +37,7 @@
 }
 
 DeviceController::~DeviceController() {
-  DCHECK(construction_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(construction_task_runner_->RunsTasksInCurrentSequence());
 }
 
 void DeviceController::Start() {
@@ -145,7 +145,7 @@
     // ownership.
     return;
   }
-  DCHECK(controller->construction_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(controller->construction_task_runner_->RunsTasksInCurrentSequence());
   bool listener_did_exist = DeleteRefCountedValueInMap(
       listener->listener_port(), &controller->listeners_);
   DCHECK(listener_did_exist);
diff --git a/tools/android/forwarder2/device_listener.cc b/tools/android/forwarder2/device_listener.cc
index 31f9687..b4c7799 100644
--- a/tools/android/forwarder2/device_listener.cc
+++ b/tools/android/forwarder2/device_listener.cc
@@ -43,7 +43,7 @@
 }
 
 DeviceListener::~DeviceListener() {
-  DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(deletion_task_runner_->RunsTasksInCurrentSequence());
   deletion_notifier_.Notify();
 }
 
diff --git a/tools/android/forwarder2/forwarders_manager.cc b/tools/android/forwarder2/forwarders_manager.cc
index c3dd026..e8b573f 100644
--- a/tools/android/forwarder2/forwarders_manager.cc
+++ b/tools/android/forwarder2/forwarders_manager.cc
@@ -50,7 +50,7 @@
 void ForwardersManager::CreateNewForwarderOnInternalThread(
     std::unique_ptr<Socket> socket1,
     std::unique_ptr<Socket> socket2) {
-  DCHECK(thread_.task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(thread_.task_runner()->RunsTasksInCurrentSequence());
   forwarders_.push_back(new Forwarder(std::move(socket1), std::move(socket2)));
 }
 
@@ -62,7 +62,7 @@
 }
 
 void ForwardersManager::WaitForEventsOnInternalThread() {
-  DCHECK(thread_.task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(thread_.task_runner()->RunsTasksInCurrentSequence());
   fd_set read_fds;
   fd_set write_fds;
 
diff --git a/tools/android/forwarder2/host_controller.cc b/tools/android/forwarder2/host_controller.cc
index f9a8e80..316794f43 100644
--- a/tools/android/forwarder2/host_controller.cc
+++ b/tools/android/forwarder2/host_controller.cc
@@ -58,7 +58,7 @@
 }
 
 HostController::~HostController() {
-  DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(deletion_task_runner_->RunsTasksInCurrentSequence());
   delete_controller_notifier_->Notify();
 }
 
diff --git a/tools/android/forwarder2/host_controllers_manager.cc b/tools/android/forwarder2/host_controllers_manager.cc
index b4bb458..9f1cf3e 100644
--- a/tools/android/forwarder2/host_controllers_manager.cc
+++ b/tools/android/forwarder2/host_controllers_manager.cc
@@ -68,7 +68,7 @@
     // then all the controllers (including |controller|) were also deleted.
     return;
   }
-  DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread());
+  DCHECK(manager->thread_->task_runner()->RunsTasksInCurrentSequence());
   // Note that this will delete |controller| which is owned by the map.
   DeleteRefCountedValueInMap(
       MakeHostControllerMapKey(controller->adb_port(),
diff --git a/tools/android/forwarder2/self_deleter_helper.h b/tools/android/forwarder2/self_deleter_helper.h
index 582f87b..b9ccc33 100644
--- a/tools/android/forwarder2/self_deleter_helper.h
+++ b/tools/android/forwarder2/self_deleter_helper.h
@@ -107,11 +107,11 @@
         weak_ptr_factory_(this) {}
 
   ~SelfDeleterHelper() {
-    DCHECK(construction_runner_->RunsTasksOnCurrentThread());
+    DCHECK(construction_runner_->RunsTasksInCurrentSequence());
   }
 
   void MaybeSelfDeleteSoon() {
-    DCHECK(!construction_runner_->RunsTasksOnCurrentThread());
+    DCHECK(!construction_runner_->RunsTasksInCurrentSequence());
     construction_runner_->PostTask(
         FROM_HERE,
         base::Bind(&SelfDeleterHelper::SelfDelete,
@@ -120,7 +120,7 @@
 
  private:
   void SelfDelete() {
-    DCHECK(construction_runner_->RunsTasksOnCurrentThread());
+    DCHECK(construction_runner_->RunsTasksInCurrentSequence());
     deletion_callback_.Run(base::WrapUnique(self_deleting_object_));
   }
 
diff --git a/tools/android/md5sum/BUILD.gn b/tools/android/md5sum/BUILD.gn
index ed47367..a8d686e 100644
--- a/tools/android/md5sum/BUILD.gn
+++ b/tools/android/md5sum/BUILD.gn
@@ -21,7 +21,7 @@
   ]
   deps = [
     "//base",
-    "//build/config/sanitizers:deps",
+    "//build/config:exe_and_shlib_deps",
   ]
 
   if (is_android && use_order_profiling) {
diff --git a/tools/battor_agent/BUILD.gn b/tools/battor_agent/BUILD.gn
index fe2ce23..1a7dc67 100644
--- a/tools/battor_agent/BUILD.gn
+++ b/tools/battor_agent/BUILD.gn
@@ -14,7 +14,7 @@
   deps = [
     ":battor_agent_lib",
     "//base",
-    "//build/config/sanitizers:deps",
+    "//build/config:exe_and_shlib_deps",
     "//build/win:default_exe_manifest",
     "//device/serial",
   ]
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc
index dc5a521..6041a8b 100644
--- a/tools/battor_agent/battor_agent.cc
+++ b/tools/battor_agent/battor_agent.cc
@@ -16,27 +16,21 @@
 
 namespace {
 
-// The maximum number of times to retry when initializing a BattOr.
-const uint8_t kMaxInitAttempts = 20;
-
-// The maximum number of times to retry the StartTracing command.
-const uint8_t kMaxStartTracingAttempts = 5;
-
-// The number of milliseconds to wait before retrying initialization.
-const uint16_t kInitRetryDelayMilliseconds = 100;
-
-// The maximum number of times to retry when reading a message.
-const uint8_t kMaxReadAttempts = 20;
-
-// The number of milliseconds to wait before trying to read a message again.
-const uint8_t kReadRetryDelayMilliseconds = 1;
+// The maximum number of times to retry a command.
+const uint8_t kMaxCommandAttempts = 10;
 
 // The amount of time we need to wait after recording a clock sync marker in
 // order to ensure that the sample we synced to doesn't get thrown out.
 const uint8_t kStopTracingClockSyncDelayMilliseconds = 100;
 
-// The number of seconds allowed for a given action before timing out.
-const uint8_t kBattOrTimeoutSeconds = 4;
+// The number of seconds to wait before retrying a command.
+const uint16_t kCommandRetryDelaySeconds = 2;
+
+// The number of seconds allowed for a control message before timing out.
+const uint8_t kBattOrControlMessageTimeoutSeconds = 2;
+
+// The number of seconds allowed for connection to open before timing out.
+const uint8_t kBattOrConnectionTimeoutSeconds = 4;
 
 // Returns true if the specified vector of bytes decodes to a message that is an
 // ack for the specified control message type.
@@ -123,9 +117,7 @@
       listener_(listener),
       last_action_(Action::INVALID),
       command_(Command::INVALID),
-      num_init_attempts_(0),
-      num_start_tracing_attempts_(0),
-      num_read_attempts_(0) {
+      num_command_attempts_(0) {
   // We don't care what thread the constructor is called on - we only care that
   // all of the other method invocations happen on the same thread.
   thread_checker_.DetachFromThread();
@@ -142,7 +134,6 @@
   clock_sync_markers_.clear();
   last_clock_sync_time_ = base::TimeTicks();
 
-  num_start_tracing_attempts_ = 1;
   command_ = Command::START_TRACING;
   PerformAction(Action::REQUEST_CONNECTION);
 }
@@ -172,13 +163,13 @@
 void BattOrAgent::BeginConnect() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  SetActionTimeout(kBattOrConnectionTimeoutSeconds);
+
   connection_->Open();
 }
 
 void BattOrAgent::OnConnectionOpened(bool success) {
-  // Return immediately if opening the connection already timed out.
-  if (timeout_callback_.IsCancelled())
-    return;
+  // Cancel timeout because the connection was opened in time.
   timeout_callback_.Cancel();
 
   if (!success) {
@@ -188,7 +179,6 @@
 
   switch (command_) {
     case Command::START_TRACING:
-      num_init_attempts_ = 1;
       PerformAction(Action::SEND_INIT);
       return;
     case Command::STOP_TRACING:
@@ -198,23 +188,17 @@
       PerformAction(Action::SEND_CURRENT_SAMPLE_REQUEST);
       return;
     case Command::GET_FIRMWARE_GIT_HASH:
-      num_init_attempts_ = 1;
       PerformAction(Action::SEND_INIT);
       return;
     case Command::INVALID:
       NOTREACHED();
+      return;
   }
 }
 
 void BattOrAgent::OnBytesSent(bool success) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // Return immediately if whatever action we were trying to perform already
-  // timed out.
-  if (timeout_callback_.IsCancelled())
-    return;
-  timeout_callback_.Cancel();
-
   if (!success) {
     CompleteCommand(BATTOR_ERROR_SEND_ERROR);
     return;
@@ -231,90 +215,56 @@
       PerformAction(Action::READ_START_TRACING_ACK);
       return;
     case Action::SEND_EEPROM_REQUEST:
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_EEPROM);
       return;
     case Action::SEND_SAMPLES_REQUEST:
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_CALIBRATION_FRAME);
       return;
     case Action::SEND_CURRENT_SAMPLE_REQUEST:
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_CURRENT_SAMPLE);
       return;
     case Action::SEND_GIT_HASH_REQUEST:
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_GIT_HASH);
       return;
     default:
-      CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+      NOTREACHED();
+      return;
   }
 }
 
 void BattOrAgent::OnMessageRead(bool success,
                                 BattOrMessageType type,
                                 std::unique_ptr<vector<char>> bytes) {
-  // Return immediately if whatever action we were trying to perform already
-  // timed out.
-  if (timeout_callback_.IsCancelled())
-    return;
-  timeout_callback_.Cancel();
-
   if (!success) {
     switch (last_action_) {
       case Action::READ_GIT_HASH:
+      case Action::READ_INIT_ACK:
+      case Action::READ_SET_GAIN_ACK:
+      case Action::READ_START_TRACING_ACK:
       case Action::READ_EEPROM:
       case Action::READ_CALIBRATION_FRAME:
       case Action::READ_DATA_FRAME:
+        RetryCommand();
+        return;
+
       case Action::READ_CURRENT_SAMPLE:
-        if (num_read_attempts_++ > kMaxReadAttempts) {
-          CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR);
-          return;
-        }
-
-        PerformDelayedAction(last_action_, base::TimeDelta::FromMilliseconds(
-                                               kReadRetryDelayMilliseconds));
-        return;
-
-      // Retry sending an INIT if it an ACK is not received.
-      case Action::SEND_INIT:
-      case Action::READ_INIT_ACK:
-        if (num_init_attempts_++ < kMaxInitAttempts) {
-          PerformDelayedAction(Action::SEND_INIT,
-              base::TimeDelta::FromMilliseconds(kInitRetryDelayMilliseconds));
-        } else {
-          CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES);
-        }
-
-        return;
-
-      case Action::READ_START_TRACING_ACK:
-        if (num_start_tracing_attempts_++ < kMaxStartTracingAttempts) {
-          num_init_attempts_ = 1;
-          PerformAction(Action::SEND_INIT);
-        } else {
-          CompleteCommand(BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES);
-        }
-
+        CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR);
         return;
 
       default:
-        CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR);
+        NOTREACHED();
         return;
     }
   }
 
+  // Successfully read a message, cancel any timeouts.
+  timeout_callback_.Cancel();
+
   switch (last_action_) {
     case Action::READ_INIT_ACK:
       if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT,
                                  *bytes)) {
-        if (num_init_attempts_++ < kMaxInitAttempts) {
-          PerformDelayedAction(Action::SEND_INIT,
-              base::TimeDelta::FromMilliseconds(kInitRetryDelayMilliseconds));
-        } else {
-          CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES);
-        }
-
+        RetryCommand();
         return;
       }
 
@@ -326,14 +276,14 @@
           PerformAction(Action::SEND_GIT_HASH_REQUEST);
           return;
         default:
-          CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+          NOTREACHED();
           return;
       }
 
     case Action::READ_SET_GAIN_ACK:
       if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN,
                                  *bytes)) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+        RetryCommand();
         return;
       }
 
@@ -343,13 +293,7 @@
     case Action::READ_START_TRACING_ACK:
       if (!IsAckOfControlCommand(
               type, BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, *bytes)) {
-        if (num_start_tracing_attempts_++ < kMaxStartTracingAttempts) {
-          num_init_attempts_ = 1;
-          PerformAction(Action::SEND_INIT);
-        } else {
-          CompleteCommand(BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES);
-        }
-
+        RetryCommand();
         return;
       }
 
@@ -359,7 +303,7 @@
     case Action::READ_EEPROM: {
       battor_eeprom_ = ParseEEPROM(type, *bytes);
       if (!battor_eeprom_) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+        RetryCommand();
         return;
       }
 
@@ -379,17 +323,16 @@
       BattOrFrameHeader frame_header;
       if (!ParseSampleFrame(type, *bytes, next_sequence_number_++,
                             &frame_header, &calibration_frame_)) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+        RetryCommand();
         return;
       }
 
       // Make sure that the calibration frame has actual samples in it.
       if (calibration_frame_.empty()) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+        RetryCommand();
         return;
       }
 
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_DATA_FRAME);
       return;
     }
@@ -399,20 +342,21 @@
       vector<RawBattOrSample> frame;
       if (!ParseSampleFrame(type, *bytes, next_sequence_number_++,
                             &frame_header, &frame)) {
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+        RetryCommand();
         return;
       }
 
       // Check for the empty frame the BattOr uses to indicate it's done
       // streaming samples.
       if (frame.empty()) {
+        // Cancel the next data frame timeout.
+        timeout_callback_.Cancel();
         CompleteCommand(BATTOR_ERROR_NONE);
         return;
       }
 
       samples_.insert(samples_.end(), frame.begin(), frame.end());
 
-      num_read_attempts_ = 1;
       PerformAction(Action::READ_DATA_FRAME);
       return;
     }
@@ -432,40 +376,32 @@
       return;
 
     case Action::READ_GIT_HASH:
-      if (type != BATTOR_MESSAGE_TYPE_CONTROL_ACK ){
-        CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+      if (type != BATTOR_MESSAGE_TYPE_CONTROL_ACK) {
+        RetryCommand();
         return;
       }
+
       firmware_git_hash_ = std::string(bytes->begin(), bytes->end());
       CompleteCommand(BATTOR_ERROR_NONE);
       return;
 
     default:
-      CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE);
+      NOTREACHED();
+      return;
   }
 }
 
 void BattOrAgent::PerformAction(Action action) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  timeout_callback_.Reset(
-      base::Bind(&BattOrAgent::OnActionTimeout, AsWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, timeout_callback_.callback(),
-      base::TimeDelta::FromSeconds(kBattOrTimeoutSeconds));
-
   last_action_ = action;
 
   switch (action) {
     case Action::REQUEST_CONNECTION:
       BeginConnect();
       return;
-
     // The following actions are required for StartTracing:
     case Action::SEND_INIT:
-      // Clear out the serial data that may exist from prior init attempts.
-      connection_->Flush();
-
       SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0);
       return;
     case Action::READ_INIT_ACK:
@@ -486,7 +422,6 @@
     case Action::READ_START_TRACING_ACK:
       connection_->ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK);
       return;
-
     // The following actions are required for StopTracing:
     case Action::SEND_EEPROM_REQUEST:
       // Read the BattOr's EEPROM to get calibration information that's required
@@ -507,6 +442,10 @@
       // data frame. We keep track of the next frame sequence number we expect
       // to see to ensure we don't miss any data.
       next_sequence_number_ = 0;
+
+      // Clear stored samples from prior attempts to read sample frames.
+      samples_.clear();
+      calibration_frame_.clear();
     case Action::READ_DATA_FRAME:
       // The first frame sent back from the BattOr contains voltage and current
       // data that excludes whatever device is being measured from the
@@ -515,6 +454,7 @@
       //
       // All further frames contain real (but uncalibrated) voltage and current
       // data.
+      SetActionTimeout(kBattOrControlMessageTimeoutSeconds);
       connection_->ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES);
       return;
 
@@ -527,7 +467,6 @@
       return;
 
     case Action::SEND_GIT_HASH_REQUEST:
-      connection_->Flush();
       SendControlMessage(
           BATTOR_CONTROL_MESSAGE_TYPE_GET_FIRMWARE_GIT_HASH, 0, 0);
       return;
@@ -538,6 +477,7 @@
 
     case Action::INVALID:
       NOTREACHED();
+      return;
   }
 }
 
@@ -550,29 +490,13 @@
 void BattOrAgent::OnActionTimeout() {
   switch (last_action_) {
     case Action::READ_INIT_ACK:
-      if (num_init_attempts_++ < kMaxInitAttempts) {
-        // OnMessageRead() will fail and retry SEND_INIT.
-        connection_->CancelReadMessage();
-      } else {
-        CompleteCommand(BATTOR_ERROR_TOO_MANY_INIT_RETRIES);
-      }
-      return;
-
-    // TODO(crbug.com/672631): There's currently a BattOr firmware bug that's
-    // causing the BattOr to reset when it's sent the START_TRACING command.
-    // When the BattOr resets, it emits 0x00 to the serial connection. This 0x00
-    // isn't long enough for the connection to consider it a full ack of the
-    // START_TRACING command, so it continues to wait for more data. We handle
-    // this case here by assuming any timeouts while waiting for the
-    // StartTracing ack are related to this bug and retrying the full
-    // initialization sequence.
+    case Action::READ_SET_GAIN_ACK:
     case Action::READ_START_TRACING_ACK:
-      if (num_start_tracing_attempts_ < kMaxStartTracingAttempts) {
-        // OnMessageRead() will fail and retry StartTracing.
-        connection_->CancelReadMessage();
-      } else {
-        CompleteCommand(BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES);
-      }
+    case Action::READ_EEPROM:
+    case Action::READ_CALIBRATION_FRAME:
+    case Action::READ_DATA_FRAME:
+    case Action::READ_GIT_HASH:
+      connection_->CancelReadMessage();
       return;
 
     default:
@@ -586,10 +510,39 @@
                                      uint16_t param2) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  SetActionTimeout(kBattOrControlMessageTimeoutSeconds);
+
   BattOrControlMessage msg{type, param1, param2};
   connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg));
 }
 
+void BattOrAgent::RetryCommand() {
+  if (++num_command_attempts_ >= kMaxCommandAttempts) {
+    CompleteCommand(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES);
+    return;
+  }
+
+  // Failed to read response to message, retry current command.
+  base::Callback<void()> next_command;
+  switch (command_) {
+    case Command::START_TRACING:
+      next_command = base::Bind(&BattOrAgent::StartTracing, AsWeakPtr());
+      break;
+    case Command::STOP_TRACING:
+      next_command = base::Bind(&BattOrAgent::StopTracing, AsWeakPtr());
+      break;
+    case Command::GET_FIRMWARE_GIT_HASH:
+      next_command = base::Bind(&BattOrAgent::GetFirmwareGitHash, AsWeakPtr());
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, next_command,
+      base::TimeDelta::FromSeconds(kCommandRetryDelaySeconds));
+}
+
 void BattOrAgent::CompleteCommand(BattOrError error) {
   switch (command_) {
     case Command::START_TRACING:
@@ -616,6 +569,7 @@
       break;
     case Command::INVALID:
       NOTREACHED();
+      return;
   }
 
   last_action_ = Action::INVALID;
@@ -625,6 +579,7 @@
   calibration_frame_.clear();
   samples_.clear();
   next_sequence_number_ = 0;
+  num_command_attempts_ = 0;
 }
 
 std::string BattOrAgent::SamplesToString() {
@@ -667,4 +622,12 @@
   return trace_stream.str();
 }
 
+void BattOrAgent::SetActionTimeout(uint16_t timeout_seconds) {
+  timeout_callback_.Reset(
+      base::Bind(&BattOrAgent::OnActionTimeout, AsWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, timeout_callback_.callback(),
+      base::TimeDelta::FromSeconds(timeout_seconds));
+}
+
 }  // namespace battor
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h
index 87be4fc..176cb70 100644
--- a/tools/battor_agent/battor_agent.h
+++ b/tools/battor_agent/battor_agent.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "tools/battor_agent/battor_connection.h"
 #include "tools/battor_agent/battor_error.h"
@@ -126,8 +127,6 @@
   // Performs an action after a delay.
   void PerformDelayedAction(Action action, base::TimeDelta delay);
 
-
-
   // Requests a connection to the BattOr.
   void BeginConnect();
 
@@ -136,12 +135,18 @@
                           uint16_t param1,
                           uint16_t param2);
 
+  // Retry the last command.
+  void RetryCommand();
+
   // Completes the command with the specified error.
   void CompleteCommand(BattOrError error);
 
   // Returns a formatted version of samples_ with timestamps and real units.
   std::string SamplesToString();
 
+  // Sets and restarts the action timeout timer.
+  void SetActionTimeout(uint16_t timeout_seconds);
+
   // The listener that handles the commands' results. It must outlive the agent.
   Listener* listener_;
 
@@ -180,14 +185,8 @@
   // we receive frames in order.
   uint32_t next_sequence_number_;
 
-  // The number of times we've attempted to init the BattOr.
-  uint8_t num_init_attempts_;
-
-  // The number of times we've attempted the BattOr StartTracing command.
-  uint8_t num_start_tracing_attempts_;
-
-  // The number of times that we've attempted to read the last message.
-  uint8_t num_read_attempts_;
+  // The number of times we've attempted a command.
+  uint8_t num_command_attempts_;
 
   // The timeout that's run when an action times out.
   base::CancelableClosure timeout_callback_;
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc
index 0d535543..e1b2461 100644
--- a/tools/battor_agent/battor_agent_bin.cc
+++ b/tools/battor_agent/battor_agent_bin.cc
@@ -44,6 +44,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc
index b8b871f..6270960 100644
--- a/tools/battor_agent/battor_agent_unittest.cc
+++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -164,6 +164,7 @@
     EEPROM_RECEIVED,
     SAMPLES_REQUEST_SENT,
     CALIBRATION_FRAME_RECEIVED,
+    SAMPLES_END_FRAME_RECEIVED,
 
     // States required to RecordClockSyncMarker.
     CURRENT_SAMPLE_REQUEST_SENT,
@@ -177,9 +178,6 @@
   // Runs BattOrAgent::StartTracing until it reaches the specified state by
   // feeding it the callbacks it needs to progress.
   void RunStartTracingTo(BattOrAgentState end_state) {
-    is_command_complete_ = false;
-
-    GetAgent()->StartTracing();
     GetTaskRunner()->RunUntilIdle();
 
     GetAgent()->OnConnectionOpened(true);
@@ -221,9 +219,6 @@
   // Runs BattOrAgent::StopTracing until it reaches the specified state by
   // feeding it the callbacks it needs to progress.
   void RunStopTracingTo(BattOrAgentState end_state) {
-    is_command_complete_ = false;
-
-    GetAgent()->StopTracing();
     GetTaskRunner()->RunUntilIdle();
 
     GetAgent()->OnConnectionOpened(true);
@@ -253,20 +248,24 @@
     if (end_state == BattOrAgentState::SAMPLES_REQUEST_SENT)
       return;
 
-    DCHECK(end_state == BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
-
     BattOrFrameHeader cal_frame_header{0, sizeof(RawBattOrSample)};
     RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
     OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
                   CreateFrame(cal_frame_header, cal_frame, 1));
+
+    if (end_state == BattOrAgentState::CALIBRATION_FRAME_RECEIVED)
+      return;
+
+    DCHECK(end_state == BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
+    BattOrFrameHeader frame_header{1, 0};
+    OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
+                  CreateFrame(frame_header, nullptr, 0));
   }
 
   // Runs BattOrAgent::RecordClockSyncMarker until it reaches the specified
   // state by feeding it the callbacks it needs to progress.
   void RunRecordClockSyncMarkerTo(BattOrAgentState end_state) {
-    is_command_complete_ = false;
-
-    GetAgent()->RecordClockSyncMarker(kClockSyncId);
     GetTaskRunner()->RunUntilIdle();
 
     GetAgent()->OnConnectionOpened(true);
@@ -289,9 +288,6 @@
   // Runs BattOrAgent::GetFirmwareGitHash until it reaches the specified
   // state by feeding it the callbacks it needs to progress.
   void RunGetFirmwareGitHashTo(BattOrAgentState end_state) {
-    is_command_complete_ = false;
-
-    GetAgent()->GetFirmwareGitHash();
     GetTaskRunner()->RunUntilIdle();
 
     GetAgent()->OnConnectionOpened(true);
@@ -348,7 +344,6 @@
   testing::InSequence s;
   EXPECT_CALL(*GetAgent()->GetConnection(), Open());
 
-  EXPECT_CALL(*GetAgent()->GetConnection(), Flush());
   BattOrControlMessage init_msg{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0};
   EXPECT_CALL(
       *GetAgent()->GetConnection(),
@@ -378,6 +373,7 @@
   EXPECT_CALL(*GetAgent()->GetConnection(),
               ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
 
+  GetAgent()->StartTracing();
   RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
@@ -395,6 +391,7 @@
 }
 
 TEST_F(BattOrAgentTest, StartTracingFailsIfInitSendFails) {
+  GetAgent()->StartTracing();
   RunStartTracingTo(BattOrAgentState::CONNECTED);
   OnBytesSent(false);
 
@@ -402,36 +399,38 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingFailsIfInitAckReadFails) {
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterInitAckReadFails) {
+  GetAgent()->StartTracing();
+
   RunStartTracingTo(BattOrAgentState::INIT_SENT);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
 
-  for (int i = 0; i < 21; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
+  EXPECT_FALSE(IsCommandComplete());
 
-    // Bytes will be sent because INIT will be retried.
-    OnBytesSent(true);
-  }
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
 
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_INIT_RETRIES, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingFailsIfInitWrongAckRead) {
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterInitWrongAckRead) {
+  GetAgent()->StartTracing();
+
   RunStartTracingTo(BattOrAgentState::INIT_SENT);
+  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
+                ToCharVector(kStartTracingAck));
 
-  for (int i = 0; i < 21; i++) {
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kStartTracingAck));
+  EXPECT_FALSE(IsCommandComplete());
 
-    // Bytes will be sent because INIT will be retried.
-    OnBytesSent(true);
-  }
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
 
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_INIT_RETRIES, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainSendFails) {
+TEST_F(BattOrAgentTest, StartTracingFailsAfterSetGainSendFails) {
+  GetAgent()->StartTracing();
+
   RunStartTracingTo(BattOrAgentState::INIT_SENT);
   OnBytesSent(false);
 
@@ -439,24 +438,37 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainAckReadFails) {
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSetGainAckReadFails) {
+  GetAgent()->StartTracing();
+
   RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT);
   OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainWrongAckRead) {
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSetGainWrongAckRead) {
+  GetAgent()->StartTracing();
+
   RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
                 ToCharVector(kStartTracingAck));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingSendFails) {
+  GetAgent()->StartTracing();
   RunStartTracingTo(BattOrAgentState::INIT_SENT);
   OnBytesSent(false);
 
@@ -464,30 +476,34 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterRetriesIfWrongAckRead) {
-  RunStartTracingTo(BattOrAgentState::CONNECTED);
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterWrongAckRead) {
+  GetAgent()->StartTracing();
 
-  for (int i = 0; i < 4; i++) {
-    // Go through the correct init sequence, but give the wrong ack to
-    // START_TRACING.
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kSetGainAck));
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-  }
+  // Go through the correct init sequence, but give the wrong ack to
+  // START_TRACING.
+  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT);
+  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
+
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
+
+  EXPECT_TRUE(IsCommandComplete());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
+}
+
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterReadFails) {
+  GetAgent()->StartTracing();
+
+  // Go through the correct init sequence, but indicate that we failed to read
+  // the START_TRACING ack.
+  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
+
+  EXPECT_FALSE(IsCommandComplete());
 
   // On the last attempt, give the correct ack to START_TRACING.
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kSetGainAck));
-  OnBytesSent(true);
+  RunStartTracingTo(BattOrAgentState::START_TRACING_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
                 ToCharVector(kStartTracingAck));
 
@@ -495,61 +511,12 @@
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StartTracingSucceedsAfterRetriesWithReadFailure) {
-  RunStartTracingTo(BattOrAgentState::CONNECTED);
+TEST_F(BattOrAgentTest, StartTracingSucceedsAfterSamplesReadDuringInit) {
+  GetAgent()->StartTracing();
 
-  for (int i = 0; i < 4; i++) {
-    // Go through the correct init sequence, but indicate that we failed to read
-    // the START_TRACING ack.
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kSetGainAck));
-    OnBytesSent(true);
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-  }
-
-  // On the last attempt, give the correct ack to START_TRACING.
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kSetGainAck));
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kStartTracingAck));
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingWrongAckReadTooMuch) {
-  RunStartTracingTo(BattOrAgentState::CONNECTED);
-
-  for (int i = 0; i < 5; i++) {
-    // Go through the correct init sequence, but give the wrong ack to
-    // START_TRACING.
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kSetGainAck));
-    OnBytesSent(true);
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kInitAck));
-  }
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StartTracingSucceedsWithOneInitFailure) {
   RunStartTracingTo(BattOrAgentState::INIT_SENT);
 
-  // Send some samples instead of an INIT ACK. This will force an INIT retry.
+  // Send some samples instead of an INIT ACK. This will force a command retry.
   BattOrFrameHeader frame_header{1, 3 * sizeof(RawBattOrSample)};
   RawBattOrSample frame[] = {
       RawBattOrSample{1, 1}, RawBattOrSample{2, 2}, RawBattOrSample{3, 3},
@@ -557,21 +524,31 @@
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
                 CreateFrame(frame_header, frame, 3));
 
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
+  EXPECT_FALSE(IsCommandComplete());
 
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kSetGainAck));
-
-  OnBytesSent(true);
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(kStartTracingAck));
+  RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE);
 
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
+TEST_F(BattOrAgentTest, StartTracingFailsAfterTooManyCumulativeFailures) {
+  GetAgent()->StartTracing();
+
+  for (int i = 0; i < 9; i++) {
+    RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT);
+    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
+
+    EXPECT_FALSE(IsCommandComplete());
+  }
+
+  RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
+
+  EXPECT_TRUE(IsCommandComplete());
+  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES, GetCommandError());
+}
+
 TEST_F(BattOrAgentTest, StopTracing) {
   testing::InSequence s;
   EXPECT_CALL(*GetAgent()->GetConnection(), Open());
@@ -601,6 +578,7 @@
               ReadMessage(BATTOR_MESSAGE_TYPE_SAMPLES))
       .Times(4);
 
+  GetAgent()->StopTracing();
   RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
 
   // Send the calibration frame.
@@ -651,6 +629,7 @@
 }
 
 TEST_F(BattOrAgentTest, StopTracingFailsIfEEPROMRequestSendFails) {
+  GetAgent()->StopTracing();
   RunStopTracingTo(BattOrAgentState::CONNECTED);
   OnBytesSent(false);
 
@@ -658,50 +637,37 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingRetriesEEPROMRead) {
-  RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT);
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterEEPROMReadFails) {
+  GetAgent()->StopTracing();
 
+  RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT);
   OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
 
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(BattOrEEPROM()));
+  EXPECT_FALSE(IsCommandComplete());
 
-  // Give confirmation that the samples request was sent.
-  OnBytesSent(true);
-
-  BattOrFrameHeader cal_frame_header{0, sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
-
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfEEPROMReadFails) {
-  RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT);
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterEEPROMWrongAckRead) {
+  GetAgent()->StopTracing();
 
-  for (int i = 0; i < 21; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
-  }
-
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingFailsIfEEPROMWrongAckRead) {
   RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfRequestSamplesFails) {
+TEST_F(BattOrAgentTest, StopTracingFailsIfSendamplesRequestFails) {
+  GetAgent()->StopTracing();
+
   RunStopTracingTo(BattOrAgentState::EEPROM_RECEIVED);
   OnBytesSent(false);
 
@@ -709,99 +675,113 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingSucceedsWithOneCalibrationFrameReadFailure) {
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameReadFailure) {
+  GetAgent()->StopTracing();
+
   RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
+  // Make a read fail in order to make sure that the agent will retry.
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
+
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
+  EXPECT_TRUE(IsCommandComplete());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
+}
+
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameReadFailure) {
+  GetAgent()->StopTracing();
+
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
 
   // Make a read fail in order to make sure that the agent will retry.
   OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
 
-  BattOrFrameHeader cal_frame_header{0, sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {RawBattOrSample{1, 1}};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
+  EXPECT_FALSE(IsCommandComplete());
 
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest, StopTracingFailsWithManyCalibrationFrameReadFailures) {
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
+  GetAgent()->StopTracing();
 
-  // We attempt the read a max of 20 times: send that many failures.
-  for (int i = 0; i < 21; i++) {
+  for (int i = 0; i < 9; i++) {
+    RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
     OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
+
+    EXPECT_FALSE(IsCommandComplete());
   }
 
-  EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
-}
-
-TEST_F(BattOrAgentTest, StopTracingSucceedsWithOneDataFrameReadFailure) {
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
-
-  // Make a read fail in order to make sure that the agent will retry.
+  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
   OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
 
-  BattOrFrameHeader frame_header{1, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, nullptr, 0));
-
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest, StopTracingFailsWithManyDataFrameReadFailures) {
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
+  GetAgent()->StopTracing();
 
-  // We attempt the read a max of 20 times: send that many failures.
-  for (int i = 0; i < 21; i++) {
+  for (int i = 0; i < 9; i++) {
+    RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
     OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
+
+    EXPECT_FALSE(IsCommandComplete());
   }
 
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingRetriesResetEachFrame) {
+TEST_F(BattOrAgentTest, StopTracingSucceedsWithFewDataFrameReadFailures) {
+  BattOrFrameHeader frame_header{1, 1 * sizeof(RawBattOrSample)};
+  RawBattOrSample frame[] = {RawBattOrSample{1, 1}};
+
+  GetAgent()->StopTracing();
+
   RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
 
-  // Send 11 failures on two different reads: because the retry count should
-  // reset after a successful read, this should still be okay.
-  for (int i = 0; i < 11; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-  }
+  EXPECT_FALSE(IsCommandComplete());
 
-  BattOrFrameHeader frame_header1{1, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame1[] = {RawBattOrSample{1, 1}};
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header1, frame1, 1));
+                CreateFrame(frame_header, frame, 1));
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
 
-  for (int i = 0; i < 11; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr);
-  }
+  EXPECT_FALSE(IsCommandComplete());
 
-  BattOrFrameHeader frame_header2{2, 0};
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header2, nullptr, 0));
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfSamplesReadHasWrongType) {
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterSamplesReadHasWrongType) {
+  GetAgent()->StopTracing();
+
   RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kInitAck));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfCalibrationFrameHasWrongLength) {
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameWrongLength) {
+  GetAgent()->StopTracing();
 
   // Send a calibration frame with a mismatch between the frame length in the
   // header and the actual frame length.
@@ -809,36 +789,41 @@
   RawBattOrSample cal_frame[] = {
       RawBattOrSample{1, 1}, RawBattOrSample{2, 2},
   };
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
                 CreateFrame(cal_frame_header, cal_frame, 2));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfDataFrameHasWrongLength) {
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
-
-  BattOrFrameHeader cal_frame_header{0, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {
-      RawBattOrSample{1, 1},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameHasWrongLength) {
+  GetAgent()->StopTracing();
 
   // Send a data frame with a mismatch between the frame length in the
   // header and the actual frame length.
   BattOrFrameHeader frame_header{1, 2 * sizeof(RawBattOrSample)};
   RawBattOrSample frame[] = {RawBattOrSample{1, 1}};
+
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
                 CreateFrame(frame_header, frame, 1));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfCalibrationFrameMissingByte) {
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterCalibrationFrameMissingByte) {
+  GetAgent()->StopTracing();
 
   BattOrFrameHeader cal_frame_header{0, 2 * sizeof(RawBattOrSample)};
   RawBattOrSample cal_frame[] = {
@@ -850,21 +835,19 @@
       CreateFrame(cal_frame_header, cal_frame, 2);
   cal_frame_bytes->pop_back();
 
+  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(cal_frame_bytes));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfDataFrameMissingByte) {
-  RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
-
-  BattOrFrameHeader cal_frame_header{0, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample cal_frame[] = {
-      RawBattOrSample{1, 1},
-  };
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(cal_frame_header, cal_frame, 1));
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameMissingByte) {
+  GetAgent()->StopTracing();
 
   BattOrFrameHeader frame_header{1, 1 * sizeof(RawBattOrSample)};
   RawBattOrSample frame[] = {RawBattOrSample{1, 1}};
@@ -874,30 +857,41 @@
       CreateFrame(frame_header, frame, 1);
   frame_bytes->pop_back();
 
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(frame_bytes));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, StopTracingFailsIfFrameArrivesOutOfOrder) {
-  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
+TEST_F(BattOrAgentTest, StopTracingSucceedsAfterDataFrameArrivesOutOfOrder) {
+  GetAgent()->StopTracing();
 
-  BattOrFrameHeader frame_header{1, 1 * sizeof(RawBattOrSample)};
-  RawBattOrSample frame[] = {RawBattOrSample{1, 1}};
-
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, frame, 1));
+  // Frame with sequence number 1.
+  BattOrFrameHeader frame_header1{1, 1 * sizeof(RawBattOrSample)};
+  RawBattOrSample frame1[] = {RawBattOrSample{1, 1}};
 
   // Skip frame with sequence number 2.
-  frame_header = BattOrFrameHeader{3, 1 * sizeof(RawBattOrSample)};
-  frame[0] = RawBattOrSample{1, 1};
+  BattOrFrameHeader frame_header3{3, 1 * sizeof(RawBattOrSample)};
+  RawBattOrSample frame3[] = {RawBattOrSample{1, 1}};
+
+  RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED);
 
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
-                CreateFrame(frame_header, frame, 1));
+                CreateFrame(frame_header1, frame1, 1));
+  OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES,
+                CreateFrame(frame_header3, frame3, 1));
+
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunStopTracingTo(BattOrAgentState::SAMPLES_END_FRAME_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest, RecordClockSyncMarker) {
@@ -915,6 +909,7 @@
   EXPECT_CALL(*GetAgent()->GetConnection(),
               ReadMessage(BATTOR_MESSAGE_TYPE_CONTROL_ACK));
 
+  GetAgent()->RecordClockSyncMarker(kClockSyncId);
   RunRecordClockSyncMarkerTo(
       BattOrAgentState::RECORD_CLOCK_SYNC_MARKER_COMPLETE);
 
@@ -924,6 +919,8 @@
 
 TEST_F(BattOrAgentTest, RecordClockSyncMarkerPrintsInStopTracingResult) {
   // Record a clock sync marker that says CLOCK_SYNC_ID happened at sample #2.
+  GetAgent()->RecordClockSyncMarker(kClockSyncId);
+
   RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT);
 
   uint32_t current_sample = 1;
@@ -933,6 +930,7 @@
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 
+  GetAgent()->StopTracing();
   RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT);
 
   // Now run StopTracing, and make sure that CLOCK_SYNC_ID gets printed out with
@@ -976,6 +974,8 @@
 }
 
 TEST_F(BattOrAgentTest, RecordClockSyncMarkerFailsIfSampleRequestSendFails) {
+  GetAgent()->RecordClockSyncMarker(kClockSyncId);
+
   RunRecordClockSyncMarkerTo(BattOrAgentState::CONNECTED);
   OnBytesSent(false);
 
@@ -983,21 +983,20 @@
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, RecordClockSyncMarkerRetriesCurrentSampleRead) {
-  RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT);
+TEST_F(BattOrAgentTest, RecordClockSyncMarkerFailsIfCurrentSampleReadFails) {
+  GetAgent()->RecordClockSyncMarker(kClockSyncId);
 
+  RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT);
   OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
 
-  uint32_t current_sample = 1;
-  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                ToCharVector(current_sample));
-
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest,
        RecordClockSyncMarkerFailsIfCurrentSampleReadHasWrongType) {
+  GetAgent()->RecordClockSyncMarker(kClockSyncId);
+
   RunRecordClockSyncMarkerTo(BattOrAgentState::CURRENT_SAMPLE_REQUEST_SENT);
 
   uint32_t current_sample = 1;
@@ -1009,7 +1008,10 @@
 }
 
 TEST_F(BattOrAgentTest, GetFirmwareGitHash) {
+  GetAgent()->GetFirmwareGitHash();
+
   RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
   EXPECT_EQ("GITHASH", GetGitHash());
@@ -1017,6 +1019,7 @@
 
 TEST_F(BattOrAgentTest, GetFirmwareGitHashFailsWithoutConnection) {
   GetAgent()->GetFirmwareGitHash();
+
   GetTaskRunner()->RunUntilIdle();
 
   GetAgent()->OnConnectionOpened(false);
@@ -1026,50 +1029,60 @@
   EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, GetFirmwareGitHashFailsIfReadHasWrongType) {
+TEST_F(BattOrAgentTest, GetFirmwareGitHashSucceedsReadHasWrongType) {
+  GetAgent()->GetFirmwareGitHash();
+
   RunGetFirmwareGitHashTo(BattOrAgentState::GIT_FIRMWARE_HASH_REQUEST_SENT);
 
   uint32_t current_sample = 1;
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL,
                 ToCharVector(current_sample));
 
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED);
+
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
 TEST_F(BattOrAgentTest, GetFirmwareGitHashFailsIfInitSendFails) {
+  GetAgent()->GetFirmwareGitHash();
+
   RunGetFirmwareGitHashTo(BattOrAgentState::CONNECTED);
+
   OnBytesSent(false);
 
   EXPECT_TRUE(IsCommandComplete());
   EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, GetFirmwareGitHashFailsIfInitAckReadFails) {
+TEST_F(BattOrAgentTest, GetFirmwareGitHashSucceedsAfterInitAckReadFails) {
+  GetAgent()->GetFirmwareGitHash();
+
   RunGetFirmwareGitHashTo(BattOrAgentState::INIT_SENT);
+  OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
 
-  for (int i =0; i < 21; i++) {
-    OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr);
+  EXPECT_FALSE(IsCommandComplete());
 
-    // Bytes will be sent because INIT will be retried.
-    OnBytesSent(true);
-  }
+  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_INIT_RETRIES, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 
-TEST_F(BattOrAgentTest, GetFirmwareGithashFailsIfInitWrongAckRead) {
-  RunGetFirmwareGitHashTo(BattOrAgentState::INIT_SENT);
-  for (int i = 0; i < 21; i++) {
-    OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
-                  ToCharVector(kStartTracingAck));
+TEST_F(BattOrAgentTest, GetFirmwareGitHashSucceedsAfterInitWrongAckRead) {
+  GetAgent()->GetFirmwareGitHash();
 
-    // Bytes will be sent because INIT will be retried.
-    OnBytesSent(true);
-  }
+  RunGetFirmwareGitHashTo(BattOrAgentState::INIT_SENT);
+  OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK,
+                ToCharVector(kStartTracingAck));
+
+  EXPECT_FALSE(IsCommandComplete());
+
+  RunGetFirmwareGitHashTo(BattOrAgentState::READ_GIT_HASH_RECEIVED);
 
   EXPECT_TRUE(IsCommandComplete());
-  EXPECT_EQ(BATTOR_ERROR_TOO_MANY_INIT_RETRIES, GetCommandError());
+  EXPECT_EQ(BATTOR_ERROR_NONE, GetCommandError());
 }
 }  // namespace battor
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc
index 0677ea08..e3dfa2d 100644
--- a/tools/battor_agent/battor_connection_impl.cc
+++ b/tools/battor_agent/battor_connection_impl.cc
@@ -80,6 +80,8 @@
 
 void BattOrConnectionImpl::Open() {
   if (io_handler_) {
+    // Opening new connection so flush serial data from old connection.
+    Flush();
     OnOpened(true);
     return;
   }
diff --git a/tools/battor_agent/battor_connection_impl.h b/tools/battor_agent/battor_connection_impl.h
index 5338615..3b32e2a 100644
--- a/tools/battor_agent/battor_connection_impl.h
+++ b/tools/battor_agent/battor_connection_impl.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "device/serial/serial.mojom.h"
 #include "tools/battor_agent/battor_connection.h"
 #include "tools/battor_agent/battor_error.h"
diff --git a/tools/battor_agent/battor_error.cc b/tools/battor_agent/battor_error.cc
index bf3bf93..ba9a7e6 100644
--- a/tools/battor_agent/battor_error.cc
+++ b/tools/battor_agent/battor_error.cc
@@ -22,10 +22,8 @@
       return "RECEIVE ERROR";
     case BATTOR_ERROR_UNEXPECTED_MESSAGE:
       return "UNEXPECTED MESSAGE";
-    case BATTOR_ERROR_TOO_MANY_INIT_RETRIES:
-      return "TOO MANY INIT RETRIES";
-    case BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES:
-      return "TOO MANY START_TRACING RETRIES";
+    case BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES:
+      return "TOO MANY COMMAND RETRIES";
   }
 
   NOTREACHED();
diff --git a/tools/battor_agent/battor_error.h b/tools/battor_agent/battor_error.h
index ff5cf41a..74401d6 100644
--- a/tools/battor_agent/battor_error.h
+++ b/tools/battor_agent/battor_error.h
@@ -17,8 +17,7 @@
   BATTOR_ERROR_SEND_ERROR,
   BATTOR_ERROR_RECEIVE_ERROR,
   BATTOR_ERROR_UNEXPECTED_MESSAGE,
-  BATTOR_ERROR_TOO_MANY_INIT_RETRIES,
-  BATTOR_ERROR_TOO_MANY_START_TRACING_RETRIES,
+  BATTOR_ERROR_TOO_MANY_COMMAND_RETRIES,
 };
 
 std::string BattOrErrorToString(BattOrError error);
diff --git a/tools/binary_size/README.md b/tools/binary_size/README.md
index f0b6439..aa5f896 100644
--- a/tools/binary_size/README.md
+++ b/tools/binary_size/README.md
@@ -10,6 +10,10 @@
 
  * https://groups.google.com/a/chromium.org/forum/#!forum/binary-size
 
+Bugs are tracked here:
+
+ * [Tools > BinarySize](https://bugs.chromium.org/p/chromium/issues/list?q=component%3ATools>BinarySize)
+
 [TOC]
 
 ## diagnose_bloat.py
@@ -27,17 +31,19 @@
 
 ### Example Usage
 
-    # Build and diff HEAD^ and HEAD.
-    tools/binary_size/diagnose_bloat.py HEAD -v
+``` bash
+# Build and diff HEAD^ and HEAD.
+tools/binary_size/diagnose_bloat.py HEAD -v
 
-    # Diff BEFORE_REV and AFTER_REV using build artifacts downloaded from perf bots.
-    tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --cloud -v
+# Diff BEFORE_REV and AFTER_REV using build artifacts downloaded from perf bots.
+tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --cloud -v
 
-    # Build and diff all contiguous revs in range BEFORE_REV..AFTER_REV for src/v8.
-    tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --subrepo v8 --all -v
+# Build and diff all contiguous revs in range BEFORE_REV..AFTER_REV for src/v8.
+tools/binary_size/diagnose_bloat.py AFTER_REV --reference-rev BEFORE_REV --subrepo v8 --all -v
 
-    # Display detailed usage info (there are many options).
-    tools/binary_size/diagnose_bloat.py -h
+# Display detailed usage info (there are many options).
+tools/binary_size/diagnose_bloat.py -h
+```
 
 ## Super Size
 
@@ -59,8 +65,9 @@
 
 1. A list of .so section sizes, as reported by `readelf -S`,
 1. Metadata (GN args, filenames, timestamps, git revision, build id),
-1. A list of symbols, including name, address, size, and associated `.o` / `.cc`
-   files.
+1. A list of symbols, including name, address, size,
+  padding (caused by alignment), and associated `.o` / `.cc` files.
+
 
 #### How are Symbols Collected?
 
@@ -73,28 +80,41 @@
      inlined symbols is gathered.
 1. Symbol aliases (when multiple symbols share an address) are collected from
    debug information via `nm elf-file`.
+   * Aliases are created by identical code folding (linker optimization).
    * Aliases have the same address and size, but report their `.pss` as
       `.size / .num_aliases`.
 1. Paths for shared symbols (those found in multiple `.o` files) are collected
    by running `nm` on every `.o` file.
-   * Shared symbols do not store the complete list of `.o` files. Instead, the
-     common ancestor is computed and stored as the path (along with a
-     `{shared}/count` suffix).
 
 #### What Other Processing Happens?
 
 1. Path normalization:
    * Prefixes are removed: `out/Release/`, `gen/`, `obj/`
    * Archive names made more pathy: `foo/bar.a(baz.o)` -> `foo/bar.a/baz.o`
+   * Shared symbols do not store the complete source paths. Instead, the
+     common ancestor is computed and stored as the path.
+      * Example: `base/{shared}/3` (the "3" means three different files contain
+        the symbol)
 
 1. Name normalization:
-   * `(anonymous::)` is removed from names.
+   * `(anonymous::)` is removed from names (and stored as a symbol flag).
+   * `[clone]` suffix removed (and stored as a symbol flag).
    * `vtable for FOO` -> `Foo [vtable]`
-   * Names split into: `name`, `template_name`, `full_name`
+   * Mangling done by linkers is undone (e.g. prefixing with "unlikely.")
+   * Names are processed into:
+     * `name`: Name without template and argument parameters
+     * `template_name`: Name without argument parameters.
+     * `full_name`: Name with all parameters.
 
 1. Clustering
-   * Compiler optimizations can cause a symbol to be broken into multiple
-     smaller symbols. Clustering puts them back together.
+   * Compiler & linker optimizations can cause symbols to be broken into
+     multiple parts to become candidates for inlining ("partial inlining").
+   * These symbols are sometimes suffixed with "`[clone]`" (removed by
+     normalization).
+   * Clustering creates groups containing all pieces of a symbol (in the case
+     where multiple pieces remain after inlining).
+   * Clustering is done by default on `SizeInfo.symbols`. To view unclustered
+     symbols, use `SizeInfo.raw_symbols`.
 
 1. Diffing
    * Some heuristics for matching up before/after symbols.
@@ -118,50 +138,76 @@
 for list of GN args to build a Release binary.
 ***
 
-Example:
+Example Usage:
 
-    ninja -C out/Release -j 1000 apks/ChromePublic.apk
-    tools/binary_size/supersize archive chrome.size --apk-file out/Release/apks/ChromePublic.apk -v
+``` bash
+# Android:
+ninja -C out/Release -j 1000 apks/ChromePublic.apk
+tools/binary_size/supersize archive chrome.size --apk-file out/Release/apks/ChromePublic.apk -v
 
-    # Linux:
-    LLVM_DOWNLOAD_GOLD_PLUGIN=1 gclient runhooks  # One-time download.
-    ninja -C out/Release -j 1000 chrome
-    tools/binary_size/supersize archive chrome.size --elf-file out/Release/chrome -v
+# Linux:
+LLVM_DOWNLOAD_GOLD_PLUGIN=1 gclient runhooks  # One-time download.
+ninja -C out/Release -j 1000 chrome
+tools/binary_size/supersize archive chrome.size --elf-file out/Release/chrome -v
+```
 
 ### Usage: html_report
 
 Creates an interactive size breakdown (by source path) as a stand-alone html
 report.
 
-Example:
+Example output: https://agrieve.github.io/supersize-chrome-android-may-16-2017/index.html
 
-    tools/binary_size/supersize html_report chrome.size --report-dir size-report -v
-    xdg-open size-report/index.html
+Example Usage:
 
-### Usage: console
-
-Starts a Python interpreter where you can run custom queries.
-
-Example:
-
-    # Prints size infomation and exits (does not enter interactive mode).
-    tools/binary_size/supersize console chrome.size --query='Print(size_info)'
-
-    # Enters a Python REPL (it will print more guidance).
-    tools/binary_size/supersize console chrome.size
+``` bash
+tools/binary_size/supersize html_report chrome.size --report-dir size-report -v
+xdg-open size-report/index.html
+```
 
 ### Usage: diff
 
 A convenience command equivalent to: `console before.size after.size --query='Print(Diff(size_info1, size_info2))'`
 
-Example
+Example Usage:
 
-    tools/binary_size/supersize diff before.size after.size --all
+``` bash
+tools/binary_size/supersize diff before.size after.size --all
+```
+
+### Usage: console
+
+Starts a Python interpreter where you can run custom queries, or run pre-made
+queries from canned_queries.py.
+
+Example Usage:
+
+```bash
+# Prints size infomation and exits (does not enter interactive mode).
+tools/binary_size/supersize console chrome.size --query='Print(size_info)'
+
+# Enters a Python REPL (it will print more guidance).
+tools/binary_size/supersize console chrome.size
+```
+
+Example session:
+
+``` python
+>>> ShowExamples()  # Get some inspiration.
+...
+>>> sorted = size_info.symbols.WhereInSection('t').Sorted()
+>>> Print(sorted)  # Have a look at the largest symbols.
+...
+>>> sym = sorted.WhereNameMatches('TrellisQuantizeBlock')[0]
+>>> Disassemble(sym)  # Time to learn assembly.
+...
+>>> help(canned_queries)
+...
+>>> Print(canned_queries.TemplatesByName(depth=-1))
+```
 
 ### Roadmap
 
-Tracked in https://crbug.com/681694
-
 1. [Better Linux support](https://bugs.chromium.org/p/chromium/issues/detail?id=717550) (clang+lld+lto vs gcc+gold).
 1. More `archive` features:
     * Find out more about 0xffffffffffffffff addresses, and why such large
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py
index 37b5e88..edaeb30e 100755
--- a/tools/binary_size/diagnose_bloat.py
+++ b/tools/binary_size/diagnose_bloat.py
@@ -77,9 +77,7 @@
 
 
 class NativeDiff(BaseDiff):
-  _RE_SUMMARY = re.compile(
-      r'.*(Section Sizes .*? object files added, \d+ removed).*',
-      flags=re.DOTALL)
+  _RE_SUMMARY = re.compile(r'Section Sizes .*?\n\n.*?(?=\n\n)', flags=re.DOTALL)
   _RE_SUMMARY_STAT = re.compile(
       r'Section Sizes \(Total=(?P<value>\d+) (?P<units>\w+)\)')
   _SUMMARY_STAT_NAME = 'Native Library Delta'
@@ -102,7 +100,7 @@
     return self._diff.splitlines()
 
   def Summary(self):
-    return NativeDiff._RE_SUMMARY.match(self._diff).group(1)
+    return NativeDiff._RE_SUMMARY.search(self._diff).group()
 
   def ProduceDiff(self, before_dir, after_dir):
     before_size = os.path.join(before_dir, self._size_name)
@@ -233,7 +231,9 @@
 
   @property
   def size_name(self):
-    return os.path.splitext(os.path.basename(self.main_lib_path))[0] + '.size'
+    if self.IsLinux():
+      return os.path.basename(self.main_lib_path) + '.size'
+    return self.apk_name + '.size'
 
   def _SetDefaults(self):
     has_goma_dir = os.path.exists(os.path.join(os.path.expanduser('~'), 'goma'))
@@ -248,6 +248,8 @@
     else:
       self.extra_gn_args_str = (' exclude_unwind_tables=true '
           'ffmpeg_branding="Chrome" proprietary_codecs=true')
+    if self.IsLinux():
+      self.extra_gn_args_str += ' allow_posix_link_time_opt=false'
     self.target = self.target if self.IsAndroid() else 'chrome'
 
   def _GenGnCmd(self):
@@ -373,7 +375,7 @@
       with open(diff_path, 'a') as diff_file:
         for d in self.diffs:
           d.RunDiff(diff_file, before.dir, after.dir)
-        logging.info('See detailed diff results here: %s.', diff_path)
+        logging.info('See detailed diff results here: %s', diff_path)
       metadata.Write()
       self._AddDiffSummaryStat(before, after)
 
@@ -755,12 +757,19 @@
   logging.basicConfig(level=log_level,
                       format='%(levelname).1s %(relativeCreated)6d %(message)s')
   build = _BuildHelper(args)
-  if build.IsCloud() and args.subrepo:
+  if build.IsCloud():
+    if args.subrepo:
       parser.error('--subrepo doesn\'t work with --cloud')
+    if build.IsLinux():
+      parser.error('--target-os linux doesn\'t work with --cloud because map '
+                   'files aren\'t generated by builders (crbug.com/716209).')
+
 
   subrepo = args.subrepo or _SRC_ROOT
-  _EnsureDirectoryClean(subrepo)
-  _SetRestoreFunc(subrepo)
+  if not build.IsCloud():
+    _EnsureDirectoryClean(subrepo)
+    _SetRestoreFunc(subrepo)
+
   if build.IsLinux():
     _VerifyUserAccepts('Linux diffs have known deficiencies (crbug/717550).')
 
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index d8aa1a4..17bd604 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -85,31 +85,59 @@
   """
   found_prefixes = set()
   for symbol in raw_symbols:
-    if symbol.full_name.startswith('*'):
+    full_name = symbol.full_name
+    if full_name.startswith('*'):
       # See comment in _CalculatePadding() about when this
       # can happen.
-      symbol.template_name = symbol.full_name
-      symbol.name = symbol.full_name
+      symbol.template_name = full_name
+      symbol.name = full_name
       continue
 
-    # E.g.: vtable for FOO
-    idx = symbol.full_name.find(' for ', 0, 30)
+    # Remove [clone] suffix, and set flag accordingly.
+    # Search from left-to-right, as multiple [clone]s can exist.
+    # Example name suffixes:
+    #     [clone .part.322]  # GCC
+    #     [clone .isra.322]  # GCC
+    #     [clone .constprop.1064]  # GCC
+    #     [clone .11064]  # clang
+    # http://unix.stackexchange.com/questions/223013/function-symbol-gets-part-suffix-after-compilation
+    idx = full_name.find(' [clone ')
     if idx != -1:
-      found_prefixes.add(symbol.full_name[:idx + 4])
-      symbol.full_name = (
-          symbol.full_name[idx + 5:] + ' [' + symbol.full_name[:idx] + ']')
+      full_name = full_name[:idx]
+      symbol.flags |= models.FLAG_CLONE
+
+    # Clones for C symbols.
+    if symbol.section == 't':
+      idx = full_name.rfind('.')
+      if idx != -1 and full_name[idx + 1:].isdigit():
+        new_name = full_name[:idx]
+        # Generated symbols that end with .123 but are not clones.
+        # Find these via:
+        #   size_info.symbols.WhereInSection('t').WhereIsGroup().SortedByCount()
+        if new_name not in ('__tcf_0', 'startup'):
+          full_name = new_name
+          symbol.flags |= models.FLAG_CLONE
+          # Remove .part / .isra / .constprop.
+          idx = full_name.rfind('.', 0, idx)
+          if idx != -1:
+            full_name = full_name[:idx]
+
+    # E.g.: vtable for FOO
+    idx = full_name.find(' for ', 0, 30)
+    if idx != -1:
+      found_prefixes.add(full_name[:idx + 4])
+      full_name = '{} [{}]'.format(full_name[idx + 5:], full_name[:idx])
 
     # E.g.: virtual thunk to FOO
-    idx = symbol.full_name.find(' to ', 0, 30)
+    idx = full_name.find(' to ', 0, 30)
     if idx != -1:
-      found_prefixes.add(symbol.full_name[:idx + 3])
-      symbol.full_name = (
-          symbol.full_name[idx + 4:] + ' [' + symbol.full_name[:idx] + ']')
+      found_prefixes.add(full_name[:idx + 3])
+      full_name = '{} [{}]'.format(full_name[idx + 4:], full_name[:idx])
 
     # Strip out return type, and split out name, template_name.
     # Function parsing also applies to non-text symbols. E.g. Function statics.
     symbol.full_name, symbol.template_name, symbol.name = (
-        function_signature.Parse(symbol.full_name))
+        function_signature.Parse(full_name))
 
     # Remove anonymous namespaces (they just harm clustering).
     symbol.template_name = symbol.template_name.replace(
@@ -164,7 +192,6 @@
 
 def _ExtractSourcePaths(raw_symbols, source_mapper):
   """Fills in the |source_path| attribute."""
-  logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count)
   for symbol in raw_symbols:
     object_path = symbol.object_path
     if object_path and not symbol.source_path:
@@ -172,8 +199,8 @@
           _SourcePathForObjectPath(object_path, source_mapper))
 
 
-def _ComputeAnscestorPath(path_list):
-  """Returns the common anscestor of the given paths."""
+def _ComputeAncestorPath(path_list):
+  """Returns the common ancestor of the given paths."""
   # Ignore missing paths.
   path_list = [p for p in path_list if p]
   prefix = os.path.commonprefix(path_list)
@@ -191,7 +218,7 @@
 
 # This must normalize object paths at the same time because normalization
 # needs to occur before finding common ancestor.
-def _ComputeAnscestorPathsAndNormalizeObjectPaths(
+def _ComputeAncestorPathsAndNormalizeObjectPaths(
     raw_symbols, object_paths_by_name, source_mapper):
   num_found_paths = 0
   num_unknown_names = 0
@@ -235,11 +262,11 @@
     if source_mapper:
       tups = [
           _SourcePathForObjectPath(p, source_mapper) for p in object_paths]
-      symbol.source_path = _ComputeAnscestorPath(t[1] for t in tups)
+      symbol.source_path = _ComputeAncestorPath(t[1] for t in tups)
       symbol.generated_source = all(t[0] for t in tups)
 
     object_paths = [_NormalizeObjectPath(p) for p in object_paths]
-    symbol.object_path = _ComputeAnscestorPath(object_paths)
+    symbol.object_path = _ComputeAncestorPath(object_paths)
 
   logging.debug('Cross-referenced %d symbols with nm output. '
                 'num_unknown_names=%d num_path_mismatches=%d '
@@ -363,16 +390,12 @@
   """Returns a SizeInfo for the given |path|."""
   logging.debug('Loading results from: %s', path)
   size_info = file_format.LoadSizeInfo(path)
-  _PostProcessSizeInfo(size_info)
-  return size_info
-
-
-def _PostProcessSizeInfo(size_info):
   logging.info('Normalizing symbol names')
   _NormalizeNames(size_info.raw_symbols)
   logging.info('Calculating padding')
   _CalculatePadding(size_info.raw_symbols)
-  logging.info('Processed %d symbols', len(size_info.raw_symbols))
+  logging.info('Loaded %d symbols', len(size_info.raw_symbols))
+  return size_info
 
 
 def CreateMetadata(map_path, elf_path, apk_path, tool_prefix, output_directory):
@@ -407,7 +430,8 @@
   return metadata
 
 
-def CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory):
+def CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory,
+                   normalize_names=True):
   """Creates a SizeInfo.
 
   Args:
@@ -425,6 +449,7 @@
     logging.info('Parsing ninja files.')
     source_mapper, elf_object_paths = ninja_parser.Parse(
         output_directory, elf_path)
+    logging.debug('Parsed %d .ninja files.', source_mapper.parsed_file_count)
     assert not elf_path or elf_object_paths, (
         'Failed to find link command in ninja files for ' +
         os.path.relpath(elf_path, output_directory))
@@ -498,7 +523,7 @@
       logging.debug('Fetched path information for %d symbols from %d files',
                     len(object_paths_by_name),
                     len(elf_object_paths) + len(missed_object_paths))
-      _ComputeAnscestorPathsAndNormalizeObjectPaths(
+      _ComputeAncestorPathsAndNormalizeObjectPaths(
           raw_symbols, object_paths_by_name, source_mapper)
 
   if not elf_path or not output_directory:
@@ -506,13 +531,19 @@
     for symbol in raw_symbols:
       symbol.object_path = _NormalizeObjectPath(symbol.object_path)
 
-  size_info = models.SizeInfo(section_sizes, raw_symbols)
-
-  # When creating the .size file, name normalization is not strictly required,
-  # but makes for smaller files.
-  # Padding not required either, but it is useful to check for large padding and
+  # Padding not really required, but it is useful to check for large padding and
   # log a warning.
-  _PostProcessSizeInfo(size_info)
+  logging.info('Calculating padding')
+  _CalculatePadding(raw_symbols)
+
+  # Do not call _NormalizeNames() during archive since that method tends to need
+  # tweaks over time. Calling it only when loading .size files allows for more
+  # flexability.
+  if normalize_names:
+    _NormalizeNames(raw_symbols)
+
+  logging.info('Processed %d symbols', len(raw_symbols))
+  size_info = models.SizeInfo(section_sizes, raw_symbols)
 
   if logging.getLogger().isEnabledFor(logging.INFO):
     for line in describe.DescribeSizeInfoCoverage(size_info):
@@ -661,7 +692,8 @@
     apk_elf_result = concurrent.ForkAndCall(
         _ElfInfoFromApk, (apk_path, apk_so_path, tool_prefix))
 
-  size_info = CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory)
+  size_info = CreateSizeInfo(map_path, elf_path, tool_prefix, output_directory,
+                             normalize_names=False)
 
   if metadata:
     size_info.metadata = metadata
diff --git a/tools/binary_size/libsupersize/canned_queries.py b/tools/binary_size/libsupersize/canned_queries.py
index 0b8a231..7785da33 100644
--- a/tools/binary_size/libsupersize/canned_queries.py
+++ b/tools/binary_size/libsupersize/canned_queries.py
@@ -14,8 +14,9 @@
 
   def Add(self, name, group):
     logging.debug('Computed %s', name)
-    group.name = name
-    self.groups.append(group)
+    sorted_group = group.Sorted()
+    sorted_group.SetName(name)
+    self.groups.append(sorted_group)
     return group.Inverted()
 
   def Finalize(self, remaining):
@@ -24,9 +25,10 @@
       stars = remaining.Filter(lambda s: s.name.startswith('*'))
       if stars:
         remaining = stars.Inverted()
-        stars.name = '** Merged Symbols'
+        stars = stars.Sorted()
+        stars.SetName('** Merged Symbols')
         self.groups.append(stars)
-      remaining.name = 'Other'
+      remaining.SetName('Other')
       self.groups.append(remaining)
 
     logging.debug('Finalized')
@@ -143,5 +145,6 @@
   def TemplatesByName(self, symbols=None, depth=0):
     """Lists C++ templates grouped by name."""
     symbols = self._SymbolsArg(symbols)
+    # Call Sorted() twice so that subgroups will be sorted.
     # TODO(agrieve): Might be nice to recursively GroupedByName() on these.
-    return symbols.WhereIsTemplate().GroupedByName(depth).Clustered().Sorted()
+    return symbols.WhereIsTemplate().Sorted().GroupedByName(depth).Sorted()
diff --git a/tools/binary_size/libsupersize/cluster_symbols.py b/tools/binary_size/libsupersize/cluster_symbols.py
deleted file mode 100644
index 61f6541..0000000
--- a/tools/binary_size/libsupersize/cluster_symbols.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Logic for clustering similar symbols."""
-
-import collections
-import logging
-import re
-
-import function_signature
-
-
-def _StripCloneSuffix(name):
-  # Multiple attributes could exist, so search from left-to-right.
-  idx = name.find(' [clone ')
-  if idx != -1:
-    return name[:idx]
-  return name
-
-
-# Refer to models.SymbolGroup.Clustered() for pydoc
-# TODO(agrieve): This logic should likely be combined with
-#    SymbolGroup.GroupedBy(), as it conceptually does the same thing.
-#    One could also thing of this as GroupedByFullName().
-def ClusterSymbols(symbols):
-  # http://unix.stackexchange.com/questions/223013/function-symbol-gets-part-suffix-after-compilation
-  # Example name suffixes:
-  #     [clone .part.322]  # GCC
-  #     [clone .isra.322]  # GCC
-  #     [clone .constprop.1064]  # GCC
-  #     [clone .11064]  # clang
-
-  # Step 1: Create name map, find clones, collect star syms into replacements.
-  logging.debug('Creating name -> symbol map')
-  clone_indices = []
-  indices_by_full_name = {}
-  # (section_name, full_name_no_attr) -> [(index, sym),...]
-  replacements_by_tup = collections.defaultdict(list)
-  for i, symbol in enumerate(symbols):
-    name = symbol.full_name
-    if not name:
-      continue
-    if name.startswith('*'):
-      # "symbol gap 3" -> "symbol gaps"
-      name = re.sub(r'\s+\d+( \(.*\))?$', 's', name)
-      replacements_by_tup[(symbol.section_name, name)].append((i, symbol))
-    elif name.endswith(']') and ' [clone ' in name:
-      clone_indices.append(i)
-    else:
-      indices_by_full_name[name] = i
-
-  # Step 2: Collect same-named clone symbols.
-  logging.debug('Grouping all clones')
-  group_names_by_index = {}
-  for i in clone_indices:
-    symbol = symbols[i]
-    stripped_full_name = _StripCloneSuffix(symbol.full_name)
-    name_tup = (symbol.section_name, stripped_full_name)
-    replacement_list = replacements_by_tup[name_tup]
-
-    if not replacement_list:
-      # First occurance, check for non-clone symbol.
-      non_clone_idx = indices_by_full_name.get(stripped_full_name)
-      if non_clone_idx is not None:
-        non_clone_symbol = symbols[non_clone_idx]
-        replacement_list.append((non_clone_idx, non_clone_symbol))
-        group_names_by_index[non_clone_idx] = stripped_full_name
-
-    replacement_list.append((i, symbol))
-    group_names_by_index[i] = stripped_full_name
-
-  # Step 3: Undo clustering when length=1.
-  # Removing these groups means Diff() logic must know about [clone] suffix.
-  to_clear = []
-  for name_tup, replacement_list in replacements_by_tup.iteritems():
-    if len(replacement_list) == 1:
-      to_clear.append(name_tup)
-  for name_tup in to_clear:
-    del replacements_by_tup[name_tup]
-
-  # Step 4: Replace first symbol from each cluster with a SymbolGroup.
-  before_symbol_count = sum(len(x) for x in replacements_by_tup.itervalues())
-  logging.debug('Creating %d symbol groups from %d symbols. %d clones had only '
-                'one symbol.', len(replacements_by_tup), before_symbol_count,
-                len(to_clear))
-
-  len_delta = len(replacements_by_tup) - before_symbol_count
-  grouped_symbols = [None] * (len(symbols) + len_delta)
-  dest_index = 0
-  src_index = 0
-  seen_tups = set()
-  index_and_name_tups = []
-  for name_tup, replacement_list in replacements_by_tup.iteritems():
-    for symbol_tup in replacement_list:
-      index_and_name_tups.append((symbol_tup[0], name_tup))
-
-  index_and_name_tups.sort(key=lambda tup: tup[0])
-  for index, name_tup in index_and_name_tups:
-    count = index - src_index
-    grouped_symbols[dest_index:dest_index + count] = (
-        symbols[src_index:src_index + count])
-    src_index = index + 1
-    dest_index += count
-    if name_tup not in seen_tups:
-      seen_tups.add(name_tup)
-      group_symbols = [tup[1] for tup in replacements_by_tup[name_tup]]
-      section_name, stripped_full_name = name_tup
-      if stripped_full_name.startswith('*'):
-        stripped_template_name = stripped_full_name
-        stripped_name = stripped_full_name
-      else:
-        stripped_template_name = _StripCloneSuffix(
-            group_symbols[0].template_name)
-        stripped_name = _StripCloneSuffix(group_symbols[0].name)
-      cluster = symbols._CreateTransformed(
-          group_symbols, full_name=stripped_full_name,
-          template_name=stripped_template_name, name=stripped_name,
-          section_name=section_name)
-      function_signature.InternSameNames(cluster)
-      grouped_symbols[dest_index] = cluster
-      dest_index += 1
-
-  assert len(grouped_symbols[dest_index:None]) == len(symbols[src_index:None])
-  grouped_symbols[dest_index:None] = symbols[src_index:None]
-  logging.debug('Finished clustering symbols.')
-  return grouped_symbols
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py
index 1e87f44..c39396b 100644
--- a/tools/binary_size/libsupersize/console.py
+++ b/tools/binary_size/libsupersize/console.py
@@ -67,6 +67,7 @@
   _readline_initialized = False
 
   def __init__(self, size_infos, size_paths, lazy_paths):
+    self._printed_variables = []
     self._variables = {
         'Print': self._PrintFunc,
         'Diff': self._DiffFunc,
@@ -74,6 +75,7 @@
         'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder,
         'ShowExamples': self._ShowExamplesFunc,
         'canned_queries': canned_queries.CannedQueries(size_infos),
+        'printed': self._printed_variables,
     }
     self._lazy_paths = lazy_paths
     self._size_infos = size_infos
@@ -86,21 +88,17 @@
       for i, size_info in enumerate(size_infos):
         self._variables['size_info%d' % (i + 1)] = size_info
 
-  def _DiffFunc(self, before=None, after=None, cluster=True, sort=True):
+  def _DiffFunc(self, before=None, after=None, sort=True):
     """Diffs two SizeInfo objects. Returns a SizeInfoDiff.
 
     Args:
       before: Defaults to first size_infos[0].
       after: Defaults to second size_infos[1].
-      cluster: When True (default), calls SymbolGroup.Clustered() after diffing.
-          Generally reduces noise.
       sort: When True (default), calls SymbolGroup.Sorted() after diffing.
     """
     before = before if before is not None else self._size_infos[0]
     after = after if after is not None else self._size_infos[1]
     ret = diff.Diff(before, after)
-    if cluster:
-      ret.symbols = ret.symbols.Clustered()
     if sort:
       ret.symbols = ret.symbols.Sorted()
     return ret
@@ -109,14 +107,22 @@
                  to_file=None):
     """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo.
 
+    For convenience, |obj| will be appended to the global "printed" list.
+
     Args:
-      obj: The object to be printed. Defaults to size_infos[-1].
+      obj: The object to be printed. Defaults to size_infos[-1]. Also accepts an
+          index into the |printed| array for showing previous results.
       verbose: Show more detailed output.
       recursive: Print children of nested SymbolGroups.
       use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol.
           default is to automatically pipe when output is long.
       to_file: Rather than print to stdio, write to the given file.
     """
+    if isinstance(obj, int):
+      obj = self._printed_variables[obj]
+    elif not self._printed_variables or self._printed_variables[-1] != obj:
+      if not isinstance(obj, models.SymbolGroup) or len(obj) > 0:
+        self._printed_variables.append(obj)
     obj = obj if obj is not None else self._size_infos[-1]
     lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive)
     _WriteToStream(lines, use_pager=use_pager, to_file=to_file)
@@ -125,12 +131,12 @@
     size_info = None
     size_path = None
     for size_info, size_path in zip(self._size_infos, self._size_paths):
-      if symbol in size_info.symbols:
+      if symbol in size_info.raw_symbols:
         break
     else:
       # If symbols is from a diff(), use its address+name to find it.
       for size_info, size_path in zip(self._size_infos, self._size_paths):
-        matched = size_info.symbols.WhereAddressInRange(symbol.address)
+        matched = size_info.raw_symbols.WhereAddressInRange(symbol.address)
         # Use last matched symbol to skip over padding-only symbols.
         if len(matched) > 0 and matched[-1].full_name == symbol.full_name:
           symbol = matched[-1]
@@ -196,6 +202,7 @@
       elf_path: Path to the executable containing the symbol. Required only
           when auto-detection fails.
     """
+    assert not symbol.IsGroup()
     assert symbol.address and symbol.section_name == '.text'
 
     tool_prefix = self._lazy_paths.tool_prefix
@@ -247,9 +254,9 @@
         'by_path = text_syms.GroupedByPath(depth=2)',
         'Print(by_path.WherePssBiggerThan(1024))',
         '',
-        '# Show all non-vtable generated symbols',
-        'generated_syms = size_info.symbols.WhereGeneratedByToolchain()',
-        'Print(generated_syms.WhereNameMatches(r"vtable").Inverted().Sorted())',
+        '# Show all generated symbols, then show only non-vtable ones',
+        'Print(size_info.symbols.WhereGeneratedByToolchain())',
+        'Print(printed[-1].WhereNameMatches(r"vtable").Inverted().Sorted())',
         '',
         '# Show all symbols that have "print" in their name or path, except',
         '# those within components/.',
@@ -264,7 +271,7 @@
         '# View per-component breakdowns, then drill into the last entry.',
         'c = canned_queries.CategorizeByChromeComponent()',
         'Print(c)',
-        'Print(c[-1].GroupedByPath(depth=2).Clustered().Sorted())',
+        'Print(c[-1].GroupedByPath(depth=2).Sorted())',
         '',
         '# For even more inspiration, look at canned_queries.py',
         '# (and feel free to add your own!).',
diff --git a/tools/binary_size/libsupersize/describe.py b/tools/binary_size/libsupersize/describe.py
index a530c3ed0..19dd064 100644
--- a/tools/binary_size/libsupersize/describe.py
+++ b/tools/binary_size/libsupersize/describe.py
@@ -10,6 +10,9 @@
 import models
 
 
+_DIFF_PREFIX_BY_STATUS = ['= ', '~ ', '+ ', '- ']
+
+
 def _PrettySize(size):
   # Arbitrarily chosen cut-off.
   if abs(size) < 2000:
@@ -37,19 +40,11 @@
   ret = str(round(pss, 1))
   if ret.endswith('.0'):
     ret = ret[:-2]
+    if ret == '0' and pss:
+      ret = '~0'
   return ret
 
 
-def _DiffPrefix(diff, sym):
-  if diff.IsAdded(sym):
-    return '+ '
-  if diff.IsRemoved(sym):
-    return '- '
-  if sym.size:
-    return '~ '
-  return '= '
-
-
 def _Divide(a, b):
   return float(a) / b if b else 0
 
@@ -137,7 +132,7 @@
           yield '{} {}'.format(' ' * indent_size, l)
         else:
           if is_diff:
-            diff_prefix = _DiffPrefix(group, s)
+            diff_prefix = _DIFF_PREFIX_BY_STATUS[group.DiffStatus(s)]
           yield '{}{}{:<4} {:>8} {:7} {}'.format(
               indent_prefix, diff_prefix, str(index) + ')',
               _FormatPss(running_total), '({:.1%})'.format(running_percent), l)
@@ -162,7 +157,9 @@
         data_size += s.pss
       elif s.section == 'b':
         bss_size += s.pss
-      unique_paths.add(s.object_path)
+      # Ignore paths like foo/{shared}/2
+      if '{' not in s.object_path:
+        unique_paths.add(s.object_path)
     header_desc = [
         'Showing {:,} symbols ({:,} unique) with total pss: {} bytes'.format(
             len(group), group.CountUniqueSymbols(), int(total_size)),
@@ -170,7 +167,7 @@
             _PrettySize(int(code_size)), _PrettySize(int(ro_size)),
             _PrettySize(int(data_size)), _PrettySize(int(bss_size)),
             _PrettySize(int(total_size))),
-        'Number of object files: {}'.format(len(unique_paths)),
+        'Number of unique paths: {}'.format(len(unique_paths)),
         '',
         'Index, Running Total, Section@Address, PSS',
         '-' * 60
@@ -178,6 +175,38 @@
     children_desc = self._DescribeSymbolGroupChildren(group)
     return itertools.chain(header_desc, children_desc)
 
+  def _DescribeDiffObjectPaths(self, diff):
+    paths_by_status = [set(), set(), set(), set()]
+    def helper(group):
+      for s in group:
+        if s.IsGroup():
+          helper(s)
+        else:
+          status = group.DiffStatus(s)
+          paths_by_status[status].add(s.source_path or s.object_path)
+    helper(diff)
+    # Show only paths that have no changed symbols (pure adds / removes).
+    unchanged, changed, added, removed = paths_by_status
+    added.difference_update(unchanged)
+    added.difference_update(changed)
+    removed.difference_update(unchanged)
+    removed.difference_update(changed)
+    yield '{} paths added, {} removed, {} changed'.format(
+        len(added), len(removed), len(changed))
+
+    if self.verbose and len(added):
+      yield 'Added files:'
+      for p in sorted(added):
+        yield '  ' + p
+    if self.verbose and len(removed):
+      yield 'Removed files:'
+      for p in sorted(removed):
+        yield '  ' + p
+    if self.verbose and len(changed):
+      yield 'Changed files:'
+      for p in sorted(changed):
+        yield '  ' + p
+
   def _DescribeSymbolDiff(self, diff):
     header_template = ('{} symbols added (+), {} changed (~), {} removed (-), '
                        '{} unchanged ({})')
@@ -185,27 +214,7 @@
     symbol_delta_desc = [header_template.format(
         diff.added_count, diff.changed_count, diff.removed_count,
         diff.unchanged_count, unchanged_msg)]
-
-    similar_paths = set()
-    added_paths = set()
-    removed_paths = set()
-    for s in diff:
-      if diff.IsAdded(s):
-        added_paths.add(s.object_path)
-      elif diff.IsRemoved(s):
-        removed_paths.add(s.object_path)
-      else:
-        similar_paths.add(s.object_path)
-    added_paths.difference_update(similar_paths)
-    removed_paths.difference_update(similar_paths)
-    path_delta_desc = ['{} object files added, {} removed'.format(
-        len(added_paths), len(removed_paths))]
-    if self.verbose and len(added_paths):
-      path_delta_desc.append('Added files:')
-      path_delta_desc.extend('  ' + p for p in sorted(added_paths))
-    if self.verbose and len(removed_paths):
-      path_delta_desc.append('Removed files:')
-      path_delta_desc.extend('  ' + p for p in sorted(removed_paths))
+    path_delta_desc = self._DescribeDiffObjectPaths(diff)
 
     diff = diff if self.verbose else diff.WhereNotUnchanged()
     group_desc = self._DescribeSymbolGroup(diff)
@@ -267,9 +276,7 @@
       expected_size = size_info.section_sizes[
           models.SECTION_TO_SECTION_NAME[section]]
 
-    # Use raw_symbols in case symbols contains groups.
-    in_section = models.SymbolGroup(size_info.raw_symbols).WhereInSection(
-        section)
+    in_section = size_info.raw_symbols.WhereInSection(section)
     actual_size = in_section.size
     size_percent = _Divide(actual_size, expected_size)
     yield ('Section {}: has {:.1%} of {} bytes accounted for from '
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py
index 4b7063c..910d72c 100644
--- a/tools/binary_size/libsupersize/diff.py
+++ b/tools/binary_size/libsupersize/diff.py
@@ -184,6 +184,6 @@
   assert isinstance(after, models.SizeInfo)
   section_sizes = {k: after.section_sizes[k] - v
                    for k, v in before.section_sizes.iteritems()}
-  symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols)
+  symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols)
   return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata,
                              after.metadata)
diff --git a/tools/binary_size/libsupersize/file_format.py b/tools/binary_size/libsupersize/file_format.py
index c13f4d3b..7be9b34 100644
--- a/tools/binary_size/libsupersize/file_format.py
+++ b/tools/binary_size/libsupersize/file_format.py
@@ -45,7 +45,7 @@
   # Store a single copy of all paths and have them referenced by index.
   # Using an OrderedDict makes the indices more repetitive (better compression).
   path_tuples = collections.OrderedDict.fromkeys(
-      (s.object_path, s.source_path) for s in size_info.symbols)
+      (s.object_path, s.source_path) for s in size_info.raw_symbols)
   for i, key in enumerate(path_tuples):
     path_tuples[key] = i
   file_obj.write('%d\n' % len(path_tuples))
@@ -53,7 +53,7 @@
   _LogSize(file_obj, 'paths')  # For libchrome, adds 200kb.
 
   # Symbol counts by section.
-  by_section = size_info.symbols.GroupedBySectionName().Sorted(
+  by_section = size_info.raw_symbols.GroupedBySectionName().Sorted(
       key=lambda s:(s[0].IsBss(), s[0].address, s.full_name))
   file_obj.write('%s\n' % '\t'.join(g.name for g in by_section))
   file_obj.write('%s\n' % '\t'.join(str(len(g)) for g in by_section))
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 3a4302b..f324ab5 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -85,6 +85,10 @@
     return subprocess.check_output(argv, env=env).splitlines()
 
 
+def _DiffCounts(sym):
+  return (sym.changed_count, sym.added_count, sym.removed_count)
+
+
 class IntegrationTest(unittest.TestCase):
   maxDiff = None  # Don't trucate diffs in errors.
   cached_size_info = [None, None, None]
@@ -122,8 +126,11 @@
     expected_size_info = self._CloneSizeInfo(
         use_output_directory=use_output_directory, use_elf=use_elf)
     self.assertEquals(expected_size_info.metadata, size_info.metadata)
-    expected = list(describe.GenerateLines(expected_size_info.Clustered()))
-    actual = list(describe.GenerateLines(size_info.Clustered()))
+    # Don't cluster.
+    expected_size_info.symbols = expected_size_info.raw_symbols
+    size_info.symbols = size_info.raw_symbols
+    expected = list(describe.GenerateLines(expected_size_info))
+    actual = list(describe.GenerateLines(size_info))
     self.assertEquals(expected, actual)
 
     sym_strs = (repr(sym) for sym in size_info.symbols)
@@ -184,7 +191,7 @@
     size_info2.symbols -= size_info2.symbols[-3:]
     size_info1.symbols[1].size -= 10
     d = diff.Diff(size_info1, size_info2)
-    d.symbols = d.symbols.Clustered().Sorted()
+    d.symbols = d.symbols.Sorted()
     return describe.GenerateLines(d, verbose=True)
 
   def test_Diff_Aliases1(self):
@@ -193,17 +200,20 @@
 
     # Removing 1 alias should not change the size.
     a1, _, _ = (
-        size_info2.symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
-    size_info2.symbols -= [a1]
+        size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
+    size_info2.raw_symbols -= [a1]
     a1.aliases.remove(a1)
     d = diff.Diff(size_info1, size_info2)
-    self.assertEquals(d.symbols.size, 0)
-    self.assertEquals(d.symbols.removed_count, 1)
+    self.assertEquals(d.raw_symbols.size, 0)
+    self.assertEquals((0, 0, 1), _DiffCounts(d.raw_symbols))
+    # shrinkToFit is in a cluster, so removed turns to a changed when clustered.
+    self.assertEquals((1, 0, 0), _DiffCounts(d.symbols.GroupedByFullName()))
 
     # Adding one alias should not change size.
     d = diff.Diff(size_info2, size_info1)
-    self.assertEquals(d.symbols.size, 0)
-    self.assertEquals(d.symbols.added_count, 1)
+    self.assertEquals(d.raw_symbols.size, 0)
+    self.assertEquals((0, 1, 0), _DiffCounts(d.raw_symbols))
+    self.assertEquals((1, 0, 0), _DiffCounts(d.symbols.GroupedByFullName()))
 
   def test_Diff_Aliases2(self):
     size_info1 = self._CloneSizeInfo()
@@ -211,18 +221,20 @@
 
     # Removing 2 aliases should not change the size.
     a1, a2, _ = (
-        size_info2.symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
-    size_info2.symbols -= [a1, a2]
+        size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
+    size_info2.raw_symbols -= [a1, a2]
     a1.aliases.remove(a1)
     a1.aliases.remove(a2)
     d = diff.Diff(size_info1, size_info2)
-    self.assertEquals(d.symbols.size, 0)
-    self.assertEquals(d.symbols.removed_count, 2)
+    self.assertEquals(d.raw_symbols.size, 0)
+    self.assertEquals((0, 0, 2), _DiffCounts(d.raw_symbols))
+    self.assertEquals((1, 0, 1), _DiffCounts(d.symbols.GroupedByFullName()))
 
     # Adding 2 aliases should not change size.
     d = diff.Diff(size_info2, size_info1)
-    self.assertEquals(d.symbols.size, 0)
-    self.assertEquals(d.symbols.added_count, 2)
+    self.assertEquals(d.raw_symbols.size, 0)
+    self.assertEquals((0, 2, 0), _DiffCounts(d.raw_symbols))
+    self.assertEquals((1, 1, 0), _DiffCounts(d.symbols.GroupedByFullName()))
 
   def test_Diff_Aliases3(self):
     size_info1 = self._CloneSizeInfo()
@@ -230,16 +242,17 @@
 
     # Removing all 3 aliases should change the size.
     a1, a2, a3 = (
-        size_info2.symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
-    size_info2.symbols -= [a1, a2, a3]
+        size_info2.raw_symbols.Filter(lambda s: s.num_aliases == 3)[0].aliases)
+    size_info2.raw_symbols -= [a1, a2, a3]
     d = diff.Diff(size_info1, size_info2)
-    self.assertEquals(d.symbols.size, -a1.size)
-    self.assertEquals(d.symbols.removed_count, 3)
+    self.assertEquals((0, 0, 3), _DiffCounts(d.raw_symbols))
+    self.assertEquals((1, 0, 2), _DiffCounts(d.symbols.GroupedByFullName()))
 
     # Adding all 3 aliases should change size.
     d = diff.Diff(size_info2, size_info1)
-    self.assertEquals(d.symbols.size, a1.size)
-    self.assertEquals(d.symbols.added_count, 3)
+    self.assertEquals(d.raw_symbols.size, a1.size)
+    self.assertEquals((0, 3, 0), _DiffCounts(d.raw_symbols))
+    self.assertEquals((1, 2, 0), _DiffCounts(d.symbols.GroupedByFullName()))
 
   def test_Diff_Clustering(self):
     size_info1 = self._CloneSizeInfo()
@@ -260,15 +273,20 @@
         models.Symbol(S, 55, name='.L__bar_295', object_path='b'), # 5
     ]
     d = diff.Diff(size_info1, size_info2)
-    d.symbols = d.symbols.Clustered().Sorted()
+    d.symbols = d.symbols.Sorted()
     self.assertEquals(d.symbols.added_count, 0)
     self.assertEquals(d.symbols.size, 0)
 
-
   @_CompareWithGolden()
   def test_FullDescription(self):
-    return describe.GenerateLines(self._CloneSizeInfo().Clustered(),
-                                  recursive=True, verbose=True)
+    size_info = self._CloneSizeInfo()
+    # Show both clustered and non-clustered so that they can be compared.
+    size_info.symbols = size_info.raw_symbols
+    return itertools.chain(
+        describe.GenerateLines(size_info, verbose=True),
+        describe.GenerateLines(size_info.symbols._Clustered(), recursive=True,
+                               verbose=True),
+    )
 
   @_CompareWithGolden()
   def test_SymbolGroupMethods(self):
diff --git a/tools/binary_size/libsupersize/linker_map_parser.py b/tools/binary_size/libsupersize/linker_map_parser.py
index 00bf04c..47d6141 100644
--- a/tools/binary_size/libsupersize/linker_map_parser.py
+++ b/tools/binary_size/libsupersize/linker_map_parser.py
@@ -111,7 +111,6 @@
 #                 0x0255fb00   0x8
 # ** common      0x02db5700   0x13ab48
     syms = self._symbols
-    symbol_gap_count = 0
     while True:
       line = self._SkipToLineWithPrefix('.')
       if not line:
@@ -133,6 +132,7 @@
             # Common symbols have no address.
             syms.extend(self._common_symbols)
           prefix_len = len(section_name) + 1  # + 1 for the trailing .
+          symbol_gap_count = 0
           merge_symbol_start_address = section_address
           sym_count_at_start = len(syms)
           line = next(self._lines)
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py
index 94259f0..a9f25bd 100644
--- a/tools/binary_size/libsupersize/models.py
+++ b/tools/binary_size/libsupersize/models.py
@@ -30,7 +30,6 @@
 import os
 import re
 
-import cluster_symbols
 import match_util
 
 
@@ -58,6 +57,12 @@
 FLAG_REL = 8
 FLAG_REL_LOCAL = 16
 FLAG_GENERATED_SOURCE = 32
+FLAG_CLONE = 64
+
+DIFF_STATUS_UNCHANGED = 0
+DIFF_STATUS_CHANGED = 1
+DIFF_STATUS_ADDED = 2
+DIFF_STATUS_REMOVED = 3
 
 
 class SizeInfo(object):
@@ -65,34 +70,37 @@
 
   Fields:
     section_sizes: A dict of section_name -> size.
-    raw_symbols: A list of all symbols, sorted by address.
-    symbols: A SymbolGroup containing all symbols. By default, these are the
-        same as raw_symbols, but may contain custom groupings when it is
-        desirable to convey the result of a query along with section_sizes and
-        metadata.
+    raw_symbols: A SymbolGroup containing all top-level symbols (no groups).
+    symbols: A SymbolGroup where symbols have been grouped by full_name (where
+        applicable). May be re-assigned when it is desirable to show custom
+        groupings while still printing metadata and section_sizes.
     metadata: A dict.
   """
   __slots__ = (
       'section_sizes',
       'raw_symbols',
-      'symbols',
+      '_symbols',
       'metadata',
   )
 
   """Root size information."""
   def __init__(self, section_sizes, raw_symbols, metadata=None, symbols=None):
+    if isinstance(raw_symbols, list):
+      raw_symbols = SymbolGroup(raw_symbols)
     self.section_sizes = section_sizes  # E.g. {'.text': 0}
     self.raw_symbols = raw_symbols
-    self.symbols = symbols or SymbolGroup(raw_symbols)
+    self._symbols = symbols
     self.metadata = metadata or {}
 
-  def Clustered(self):
-    """Returns a new SizeInfo with some symbols moved into subgroups.
+  @property
+  def symbols(self):
+    if self._symbols is None:
+      self._symbols = self.raw_symbols._Clustered()
+    return self._symbols
 
-    See SymbolGroup.Clustered() for more details.
-    """
-    return SizeInfo(self.section_sizes, self.raw_symbols, self.metadata,
-                    symbols=self.symbols.Clustered())
+  @symbols.setter
+  def symbols(self, value):
+    self._symbols = value
 
 
 class SizeInfoDiff(object):
@@ -100,22 +108,38 @@
 
   Fields:
     section_sizes: A dict of section_name -> size delta.
-    symbols: A SymbolDiff with all symbols in it.
+    raw_symbols: A SymbolDiff with all top-level symbols in it (no groups).
+    symbols: A SymbolDiff where symbols have been grouped by full_name (where
+        applicable). May be re-assigned when it is desirable to show custom
+        groupings while still printing metadata and section_sizes.
     before_metadata: metadata of the "before" SizeInfo.
     after_metadata: metadata of the "after" SizeInfo.
   """
   __slots__ = (
       'section_sizes',
-      'symbols',
+      'raw_symbols',
+      '_symbols',
       'before_metadata',
       'after_metadata',
   )
 
-  def __init__(self, section_sizes, symbols, before_metadata, after_metadata):
+  def __init__(self, section_sizes, raw_symbols, before_metadata,
+               after_metadata):
     self.section_sizes = section_sizes
-    self.symbols = symbols
+    self.raw_symbols = raw_symbols
     self.before_metadata = before_metadata
     self.after_metadata = after_metadata
+    self._symbols = None
+
+  @property
+  def symbols(self):
+    if self._symbols is None:
+      self._symbols = self.raw_symbols._Clustered()
+    return self._symbols
+
+  @symbols.setter
+  def symbols(self, value):
+    self._symbols = value
 
 
 class BaseSymbol(object):
@@ -178,6 +202,8 @@
       parts.append('rel.loc')
     if flags & FLAG_GENERATED_SOURCE:
       parts.append('gen')
+    if flags & FLAG_CLONE:
+      parts.append('clone')
     # Not actually a part of flags, but useful to show it here.
     if self.aliases:
       parts.append('{} aliases'.format(self.num_aliases))
@@ -299,7 +325,7 @@
     return len(self._symbols)
 
   def __eq__(self, other):
-    return self._symbols == other._symbols
+    return isinstance(other, SymbolGroup) and self._symbols == other._symbols
 
   def __getitem__(self, key):
     """|key| can be an index or an address.
@@ -378,6 +404,11 @@
   def IsGroup(self):
     return True
 
+  def SetName(self, full_name, template_name=None, name=None):
+    self.full_name = full_name
+    self.template_name = full_name if template_name is None else template_name
+    self.name = full_name if name is None else name
+
   def IterUniqueSymbols(self):
     """Yields all symbols, but only one from each alias group."""
     seen_aliases_lists = set()
@@ -410,18 +441,6 @@
                        name=name, section_name=section_name,
                        is_sorted=is_sorted)
 
-  def Clustered(self):
-    """Returns a new SymbolGroup with some symbols moved into subgroups.
-
-    Subgroups include:
-     * Symbols that have [clone] in their name (created during inlining).
-     * Star symbols (such as "** merge strings", and "** symbol gap")
-
-    To view created groups:
-      Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True)
-    """
-    return self._CreateTransformed(cluster_symbols.ClusterSymbols(self))
-
   def Sorted(self, cmp_func=None, key=None, reverse=False):
     if cmp_func is None and key is None:
       cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.pss), a.name),
@@ -457,6 +476,9 @@
                                    filtered_symbols=filtered_and_kept[0],
                                    section_name=self.section_name)
 
+  def WhereIsGroup(self):
+    return self.Filter(lambda s: s.IsGroup())
+
   def WhereSizeBiggerThan(self, min_size):
     return self.Filter(lambda s: s.size >= min_size)
 
@@ -547,51 +569,131 @@
     return self._CreateTransformed(
         self._filtered_symbols, filtered_symbols=self._symbols, is_sorted=False)
 
-  def GroupedBy(self, func, min_count=0):
+  def GroupedBy(self, func, min_count=0, group_factory=None):
     """Returns a SymbolGroup of SymbolGroups, indexed by |func|.
 
     Symbols within each subgroup maintain their relative ordering.
 
     Args:
       func: Grouping function. Passed a symbol and returns a string for the
-            name of the subgroup to put the symbol in. If None is returned, the
-            symbol is omitted.
+          name of the subgroup to put the symbol in. If None is returned, the
+          symbol is omitted.
       min_count: Miniumum number of symbols for a group. If fewer than this many
-                 symbols end up in a group, they will not be put within a group.
-                 Use a negative value to omit symbols entirely rather than
-                 include them outside of a group.
+          symbols end up in a group, they will not be put within a group.
+          Use a negative value to omit symbols entirely rather than
+          include them outside of a group.
+      group_factory: Function to create SymbolGroup from a list of Symbols.
     """
+    if group_factory is None:
+      group_factory = lambda token, symbols: self._CreateTransformed(
+            symbols, full_name=token, template_name=token, name=token,
+            section_name=self.section_name)
+
     after_syms = []
     filtered_symbols = []
-    symbols_by_token = collections.defaultdict(list)
+    symbols_by_token = collections.OrderedDict()
     # Index symbols by |func|.
     for symbol in self:
       token = func(symbol)
       if token is None:
         filtered_symbols.append(symbol)
-      symbols_by_token[token].append(symbol)
+      else:
+        # Optimization: Store a list only when >1 symbol.
+        # Saves 200-300ms for _Clustered().
+        prev = symbols_by_token.setdefault(token, symbol)
+        if prev is not symbol:
+          if prev.__class__ == list:
+            prev.append(symbol)
+          else:
+            symbols_by_token[token] = [prev, symbol]
     # Create the subgroups.
     include_singles = min_count >= 0
     min_count = abs(min_count)
-    for token, symbols in symbols_by_token.iteritems():
-      if len(symbols) >= min_count:
-        after_syms.append(self._CreateTransformed(
-            symbols, name=token, section_name=self.section_name,
-            is_sorted=False))
-      elif include_singles:
-        after_syms.extend(symbols)
+    for token, symbol_or_list in symbols_by_token.iteritems():
+      count = 1
+      if symbol_or_list.__class__ == list:
+        count = len(symbol_or_list)
+
+      if count >= min_count:
+        if count == 1:
+          symbol_or_list = [symbol_or_list]
+        after_syms.append(group_factory(token, symbol_or_list))
       else:
-        filtered_symbols.extend(symbols)
-    grouped = self._CreateTransformed(
+        target_list = after_syms if include_singles else filtered_symbols
+        if count == 1:
+          target_list.append(symbol_or_list)
+        else:
+          target_list.extend(symbol_or_list)
+
+    return self._CreateTransformed(
         after_syms, filtered_symbols=filtered_symbols,
-        section_name=self.section_name, is_sorted=False)
-    return grouped
+        section_name=self.section_name)
+
+  def _Clustered(self):
+    """Returns a new SymbolGroup with some symbols moved into subgroups.
+
+    Method is private since it only ever makes sense to call it from
+    SizeInfo.symbols.
+
+    The main function of clustering is to put symbols that were broken into
+    multiple parts under a group so that they once again look like a single
+    symbol. It also groups together symbols like "** merge strings".
+
+    To view created groups:
+      Print(size_info.symbols.WhereIsGroup())
+    """
+    def cluster_func(symbol):
+      name = symbol.full_name
+      if not name:
+        # min_count=2 will ensure order is maintained while not being grouped.
+        # "&" to distinguish from real symbol names, id() to ensure uniqueness.
+        name = '&' + hex(id(symbol))
+      elif name.startswith('*'):
+        # "symbol gap 3" -> "symbol gaps"
+        name = re.sub(r'\s+\d+( \(.*\))?$', 's', name)
+      # Never cluster symbols that span multiple paths so that all groups return
+      # non-None path information.
+      return (symbol.object_path, name)
+
+    # Use a custom factory to fill in name & template_name.
+    def group_factory(token, symbols):
+      full_name = token[1]
+      sym = symbols[0]
+      if token[1].startswith('*'):
+        return self._CreateTransformed(
+            symbols, full_name=full_name, template_name=full_name,
+            name=full_name, section_name=sym.section_name)
+      return self._CreateTransformed(
+          symbols, full_name=full_name, template_name=sym.template_name,
+          name=sym.name, section_name=sym.section_name)
+
+    # A full second faster to cluster per-section. Plus, don't need create
+    # (section_name, name) tuples in cluster_func.
+    ret = []
+    for section in self.GroupedBySectionName():
+      ret.extend(section.GroupedBy(
+          cluster_func, min_count=2, group_factory=group_factory))
+
+    return self._CreateTransformed(ret)
 
   def GroupedBySectionName(self):
     return self.GroupedBy(lambda s: s.section_name)
 
+  def GroupedByFullName(self, min_count=2):
+    """Groups by symbol.full_name.
+
+    Does not differentiate between namespaces/classes/functions.
+
+    Args:
+      min_count: Miniumum number of symbols for a group. If fewer than this many
+                 symbols end up in a group, they will not be put within a group.
+                 Use a negative value to omit symbols entirely rather than
+                 include them outside of a group.
+    """
+    return self.GroupedBy(lambda s: s.full_name, min_count=min_count)
+
   def GroupedByName(self, depth=0, min_count=0):
-    """Groups by symbol name, where |depth| controls how many ::s to include.
+    """Groups by symbol.name, where |depth| controls how many ::s to include.
 
     Does not differentiate between namespaces/classes/functions.
 
@@ -649,11 +751,15 @@
   __slots__ = (
       '_added_ids',
       '_removed_ids',
+      '_diff_status',
+      '_changed_count',
   )
 
   def __init__(self, added, removed, similar):
     self._added_ids = set(id(s) for s in added)
     self._removed_ids = set(id(s) for s in removed)
+    self._diff_status = DIFF_STATUS_CHANGED
+    self._changed_count = None
     symbols = []
     symbols.extend(added)
     symbols.extend(removed)
@@ -668,38 +774,28 @@
   def _CreateTransformed(self, symbols, filtered_symbols=None, full_name=None,
                          template_name=None, name=None, section_name=None,
                          is_sorted=None):
-    # Printing sorts, so short-circuit the same symbols case.
-    if len(symbols) == len(self._symbols):
-      new_added_ids = self._added_ids
-      new_removed_ids = self._removed_ids
-    else:
-      old_added_ids = self._added_ids
-      old_removed_ids = self._removed_ids
-
-      def get_status(sym):
-        obj_id = id(sym)
-        if obj_id in old_added_ids:
-          return 0
-        if obj_id in old_removed_ids:
-          return 1
-        if sym.IsGroup():
-          first_status = get_status(sym[0])
-          if all(get_status(s) == first_status for s in sym[1:]):
-            return first_status
-        return 2
-
-      new_added_ids = set()
-      new_removed_ids = set()
+    new_added_ids = set()
+    new_removed_ids = set()
+    group_diff_status = DIFF_STATUS_UNCHANGED
+    changed_count = 0
+    if symbols:
+      group_diff_status = self.DiffStatus(symbols[0])
       for sym in symbols:
-        status = get_status(sym)
-        if status == 0:
+        status = self.DiffStatus(sym)
+        if status != group_diff_status:
+          group_diff_status = DIFF_STATUS_CHANGED
+        if status == DIFF_STATUS_ADDED:
           new_added_ids.add(id(sym))
-        elif status == 1:
+        elif status == DIFF_STATUS_REMOVED:
           new_removed_ids.add(id(sym))
+        elif status == DIFF_STATUS_CHANGED:
+          changed_count += 1
 
     ret = SymbolDiff.__new__(SymbolDiff)
     ret._added_ids = new_added_ids
     ret._removed_ids = new_removed_ids
+    ret._diff_status = group_diff_status
+    ret._changed_count = changed_count
     super(SymbolDiff, ret).__init__(
         symbols, filtered_symbols=filtered_symbols, full_name=full_name,
         template_name=template_name, name=name, section_name=section_name,
@@ -716,25 +812,42 @@
 
   @property
   def changed_count(self):
-    not_changed = self.unchanged_count + self.added_count + self.removed_count
-    return len(self) - not_changed
+    if self._changed_count is None:
+      self._changed_count = sum(1 for s in self if self.IsChanged(s))
+    return self._changed_count
 
   @property
   def unchanged_count(self):
-    return sum(1 for s in self if self.IsSimilar(s) and s.size == 0)
+    return (len(self) - self.changed_count - self.added_count -
+            self.removed_count)
+
+  def DiffStatus(self, sym):
+    # Groups store their own status, computed during _CreateTransformed().
+    if sym.IsGroup():
+      return sym._diff_status
+    sym_id = id(sym)
+    if sym_id in self._added_ids:
+      return DIFF_STATUS_ADDED
+    if sym_id in self._removed_ids:
+      return DIFF_STATUS_REMOVED
+    # 0 --> unchanged
+    # 1 --> changed
+    return int(sym.size != 0)
+
+  def IsUnchanged(self, sym):
+    return self.DiffStatus(sym) == DIFF_STATUS_UNCHANGED
+
+  def IsChanged(self, sym):
+    return self.DiffStatus(sym) == DIFF_STATUS_CHANGED
 
   def IsAdded(self, sym):
-    return id(sym) in self._added_ids
-
-  def IsSimilar(self, sym):
-    key = id(sym)
-    return key not in self._added_ids and key not in self._removed_ids
+    return self.DiffStatus(sym) == DIFF_STATUS_ADDED
 
   def IsRemoved(self, sym):
-    return id(sym) in self._removed_ids
+    return self.DiffStatus(sym) == DIFF_STATUS_REMOVED
 
   def WhereNotUnchanged(self):
-    return self.Filter(lambda s: not self.IsSimilar(s) or s.size)
+    return self.Filter(lambda s: not self.IsUnchanged(s))
 
 
 def _ExtractPrefixBeforeSeparator(string, separator, count):
diff --git a/tools/binary_size/libsupersize/nm.py b/tools/binary_size/libsupersize/nm.py
index bb75732..5a711c96 100644
--- a/tools/binary_size/libsupersize/nm.py
+++ b/tools/binary_size/libsupersize/nm.py
@@ -21,12 +21,48 @@
   # Skip lines like:
   # 00000000 t $t
   # 00000000 r $d
+  # 0000041b r .L.str
   # 0000041b r .L.str.38
   # 00000344 N
-  return name and not name.startswith('.L.str.') and not (
+  return name and not name.startswith('.L.str') and not (
       len(name) == 2 and name.startswith('$'))
 
 
+def _IsRelevantObjectFileName(name):
+  # Prevent marking compiler-generated symbols as candidates for shared paths.
+  # E.g., multiple files might have "CSWTCH.12", but they are different symbols.
+  #
+  # Find these via:
+  #   size_info.symbols.GroupedByFullName(min_count=-2).Filter(
+  #       lambda s: s.WhereObjectPathMatches('{')).SortedByCount()
+  # and then search for {shared}.
+  # List of names this applies to:
+  #   startup
+  #   __tcf_0  <-- Generated for global destructors.
+  #   ._79
+  #   .Lswitch.table, .Lswitch.table.12
+  #   CSWTCH.12
+  #   lock.12
+  #   table.12
+  #   __compound_literal.12
+  #   .L.ref.tmp.1
+  #   .L.str, .L.str.3
+  if name in ('__tcf_0', 'startup'):
+    return False
+  if name.startswith('._') and name[2:].isdigit():
+    return False
+  if name.startswith('.L') and name.find('.', 2) != -1:
+    return False
+
+  dot_idx = name.find('.')
+  if dot_idx == -1:
+    return True
+  name = name[:dot_idx]
+
+  return name not in (
+      'CSWTCH', 'lock', '__compound_literal', '__func__', 'table')
+
+
 def CollectAliasesByAddress(elf_path, tool_prefix):
   """Runs nm on |elf_path| and returns a dict of address->[names]"""
   names_by_address = collections.defaultdict(list)
@@ -87,7 +123,7 @@
       break
     space_idx = line.find(' ')  # Skip over address.
     name = line[space_idx + 3:]
-    if _IsRelevantNmName(name):
+    if _IsRelevantNmName(name) and _IsRelevantObjectFileName(name):
       ret.append(name)
   return ret
 
diff --git a/tools/binary_size/libsupersize/testdata/Archive.golden b/tools/binary_size/libsupersize/testdata/Archive.golden
index 9701955..4fa292f 100644
--- a/tools/binary_size/libsupersize/testdata/Archive.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive.golden
@@ -24,21 +24,21 @@
 .text@28f1c8(size_without_padding=20,padding=8,full_name=_GLOBAL__sub_I_SkDeviceProfile.cpp,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={startup})
 .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={unlikely})
 .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={})
-.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2],object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={})
+.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={clone})
 .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={})
 .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={})
-.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks() [clone .part.1],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon})
+.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon,clone})
 .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={})
 .rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={})
-.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 2,object_path=,source_path=,flags={})
+.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={})
 .rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=,flags={})
 .rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=,flags={})
 .rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={})
 .rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon})
 .rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={anon})
-.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={})
 .data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={})
 .data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=,flags={})
 .data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={})
@@ -47,13 +47,13 @@
 .data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=,flags={})
 .data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=,flags={})
 .data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=,flags={})
-.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=,flags={})
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={})
 .data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={rel})
 .data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon})
 .data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=,flags={anon,rel.loc})
-.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=,flags={})
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
index 59a0cbd..420ccb2 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -33,23 +33,23 @@
 .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={unlikely,gen})
 .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=,source_path=,flags={2 aliases})
 .text@2a0000(size_without_padding=16,padding=32,full_name=BazAlias(bool),object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen,2 aliases})
-.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2],object_path=third_party/{shared}/2,source_path=third_party/{shared}/2,flags={3 aliases})
+.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/{shared}/2,source_path=third_party/{shared}/2,flags={clone,3 aliases})
 .text@2a0010(size_without_padding=12,padding=0,full_name=FooAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={3 aliases})
 .text@2a0010(size_without_padding=12,padding=0,full_name=BarAlias(),object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={3 aliases})
 .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={})
-.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks() [clone .part.1],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon})
+.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,clone})
 .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={})
 .rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={})
-.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 2,object_path=,source_path=,flags={})
+.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={})
 .rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon})
 .rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon})
-.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={})
 .data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen})
 .data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen})
 .data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
@@ -58,13 +58,13 @@
 .data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={})
 .data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
-.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel})
 .data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon})
 .data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc})
-.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=third_party/fft_fixed.cc,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={})
diff --git a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
index e35c477a7..79373e4 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
@@ -24,21 +24,21 @@
 .text@28f1c8(size_without_padding=20,padding=8,full_name=_GLOBAL__sub_I_SkDeviceProfile.cpp,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={startup,gen})
 .text@28f1e0(size_without_padding=69120,padding=4,full_name=foo_bar,object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={unlikely,gen})
 .text@2a0000(size_without_padding=16,padding=32,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={})
-.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={})
+.text@2a0010(size_without_padding=12,padding=0,full_name=blink::ContiguousContainerBase::shrinkToFit(),object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={clone})
 .text@2a0020(size_without_padding=24,padding=4,full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .text@2a1000(size_without_padding=0,padding=4040,full_name=** symbol gap 1,object_path=,source_path=,flags={})
-.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks() [clone .part.1],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon})
+.text@2a1000(size_without_padding=94,padding=0,full_name=blink::PaintChunker::releasePaintChunks(),object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,clone})
 .text@24ca628(size_without_padding=0,padding=35821002,full_name=** symbol gap 2 (end of section),object_path=,source_path=,flags={})
 .rodata@266e600(size_without_padding=1961984,padding=0,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@284d600(size_without_padding=3425,padding=0,full_name=** merge constants,object_path=,source_path=,flags={})
-.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 2,object_path=,source_path=,flags={})
+.rodata@284e364(size_without_padding=0,padding=3,full_name=** symbol gap 0,object_path=,source_path=,flags={})
 .rodata@284e364(size_without_padding=8,padding=0,full_name=,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .rodata@284e370(size_without_padding=40,padding=4,full_name=Name,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .rodata@284e398(size_without_padding=32,padding=0,full_name=chrome::mojom::FilePatcher::Name_,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .rodata@284e518(size_without_padding=675633,padding=352,full_name=** merge strings,object_path=,source_path=,flags={})
 .rodata@28f3450(size_without_padding=48,padding=7,full_name=kAnimationFrameTimeHistogramClassPath,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon})
 .rodata@28f3480(size_without_padding=4,padding=0,full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list,object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={anon})
-.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.rodata@2c158e4(size_without_padding=0,padding=3286112,full_name=** symbol gap 1 (end of section),object_path=,source_path=,flags={})
 .data.rel.ro.local@2c176f0(size_without_padding=56,padding=0,full_name=ChromeMainDelegate [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen})
 .data.rel.ro.local@2c17728(size_without_padding=24,padding=0,full_name=chrome::mojom::FieldTrialRecorder [vtable],object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen})
 .data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
@@ -47,13 +47,13 @@
 .data.rel.ro@2cd8500(size_without_padding=56,padding=0,full_name=ChromeMainDelegateAndroid [vtable],object_path=third_party/WebKit.a/PaintChunker.o,source_path=third_party/paint.cc,flags={})
 .data.rel.ro@2cd8538(size_without_padding=24,padding=0,full_name=mojo::MessageReceiver [vtable],object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .data.rel.ro@2cd8550(size_without_padding=12,padding=0,full_name=kMethodsAnimationFrameTimeHistogram,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
-.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data.rel.ro@2ddc608(size_without_padding=0,padding=1065132,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={})
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={})
 .data@2de7008(size_without_padding=152,padding=0,full_name=base::android::kBaseRegisteredMethods,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={rel})
 .data@2de70a0(size_without_padding=4,padding=0,full_name=base::android::g_renderer_histogram_code,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon})
 .data@2de70a4(size_without_padding=4,padding=0,full_name=base::android::g_library_version_number,object_path=third_party/WebKit.a/ContiguousContainer.o,source_path=third_party/container.c,flags={anon,rel.loc})
-.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 3 (end of section),object_path=,source_path=,flags={})
+.data@2dffd88(size_without_padding=0,padding=101600,full_name=** symbol gap 0 (end of section),object_path=,source_path=,flags={})
 .bss@0(size_without_padding=262144,padding=0,full_name=ff_cos_131072,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_131072_fixed,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o,source_path=third_party/fft_fixed.cc,flags={})
 .bss@0(size_without_padding=131072,padding=0,full_name=ff_cos_65536,object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o,source_path=third_party/fft_float.cc,flags={})
diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden
index c8a315129..4208cc1 100644
--- a/tools/binary_size/libsupersize/testdata/Console.golden
+++ b/tools/binary_size/libsupersize/testdata/Console.golden
@@ -1,17 +1,17 @@
 ********************************************************************************
 Entering interactive Python shell. Quick reference:
 
-SizeInfo: Clustered, metadata, raw_symbols, section_sizes, symbols
+SizeInfo: metadata, raw_symbols, section_sizes, symbols
 Symbol: FlagsString, IsBss, IsGeneratedByToolchain, IsGroup, address, aliases, end_address, flags, full_name, generated_source, is_anonymous, name, num_aliases, object_path, padding, pss, pss_without_padding, section, section_name, size, size_without_padding, source_path, template_name
 
-SymbolGroup (extends Symbol): Clustered, CountUniqueSymbols, Filter, GroupedBy, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterLeafSymbols, IterUniqueSymbols, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, is_sorted
+SymbolGroup (extends Symbol): CountUniqueSymbols, Filter, GroupedBy, GroupedByFullName, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterLeafSymbols, IterUniqueSymbols, SetName, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasPath, WhereInSection, WhereIsGroup, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, is_sorted
 
-SymbolDiff (extends SymbolGroup): IsAdded, IsRemoved, IsSimilar, WhereNotUnchanged, added_count, changed_count, removed_count, unchanged_count
+SymbolDiff (extends SymbolGroup): DiffStatus, IsAdded, IsChanged, IsRemoved, IsUnchanged, WhereNotUnchanged, added_count, changed_count, removed_count, unchanged_count
 
 canned_queries: CategorizeByChromeComponent, CategorizeGenerated, TemplatesByName
 
 Functions: Diff(), Disassemble(), ExpandRegex(), Print(), ShowExamples()
-Variables: canned_queries, size_info
+Variables: canned_queries, printed, size_info
 ********************************************************************************
 # Show pydoc for main types:
 import models
@@ -25,9 +25,9 @@
 by_path = text_syms.GroupedByPath(depth=2)
 Print(by_path.WherePssBiggerThan(1024))
 
-# Show all non-vtable generated symbols
-generated_syms = size_info.symbols.WhereGeneratedByToolchain()
-Print(generated_syms.WhereNameMatches(r"vtable").Inverted().Sorted())
+# Show all generated symbols, then show only non-vtable ones
+Print(size_info.symbols.WhereGeneratedByToolchain())
+Print(printed[-1].WhereNameMatches(r"vtable").Inverted().Sorted())
 
 # Show all symbols that have "print" in their name or path, except
 # those within components/.
@@ -42,7 +42,7 @@
 # View per-component breakdowns, then drill into the last entry.
 c = canned_queries.CategorizeByChromeComponent()
 Print(c)
-Print(c[-1].GroupedByPath(depth=2).Clustered().Sorted())
+Print(c[-1].GroupedByPath(depth=2).Sorted())
 
 # For even more inspiration, look at canned_queries.py
 # (and feel free to add your own!).
@@ -64,9 +64,9 @@
     .rodata: 5.65mb (5927652 bytes) (13.5%)
     .text: 34.2mb (35900712 bytes) (82.0%)
 
-Showing 49 symbols (46 unique) with total pss: 43785380 bytes
+Showing 45 symbols (42 unique) with total pss: 43785380 bytes
 .text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
@@ -80,90 +80,82 @@
              extFromUUseMapping
 4)        170 (0.0%)  t@0x28d98a   32      base/page_allocator.cc
              extFromUUseMapping
-5)       5888 (0.0%)  t@0x28f000   5718    {no path}
-             ** symbol gap 0
-6)       6336 (0.0%)  t@0x28f000   448     third_party/icu/ucnv_ext.c
+5)   35830930 (81.8%) t@Group      35830760 {no path}
+             ** symbol gaps (count=3)
+6)   35831378 (81.8%) t@0x28f000   448     third_party/icu/ucnv_ext.c
              ucnv_extMatchFromU
-7)       6364 (0.0%)  t@0x28f1c8   28      third_party/icu/ucnv_ext.c
+7)   35831406 (81.8%) t@0x28f1c8   28      third_party/icu/ucnv_ext.c
              _GLOBAL__sub_I_SkDeviceProfile.cpp
-8)      75488 (0.2%)  t@0x28f1e0   69124   third_party/icu/ucnv_ext.c
+8)   35900530 (82.0%) t@0x28f1e0   69124   third_party/icu/ucnv_ext.c
              foo_bar
-9)      75512 (0.2%)  t@0x2a0000   24      {no path}
+9)   35900554 (82.0%) t@0x2a0000   24      {no path}
              blink::ContiguousContainerBase::shrinkToFit
-10)     75536 (0.2%)  t@0x2a0000   24      third_party/icu/ucnv_ext.c
+10)  35900578 (82.0%) t@0x2a0000   24      third_party/icu/ucnv_ext.c
              BazAlias
-11)     75540 (0.2%)  t@0x2a0010   4       third_party/{shared}/2
-             blink::ContiguousContainerBase::shrinkToFit [clone .part.1234] [clone .isra.2]
-12)     75544 (0.2%)  t@0x2a0010   4       third_party/fft_float.cc
+11)  35900582 (82.0%) t@0x2a0010   4       third_party/{shared}/2
+             blink::ContiguousContainerBase::shrinkToFit
+12)  35900586 (82.0%) t@0x2a0010   4       third_party/fft_float.cc
              FooAlias
-13)     75548 (0.2%)  t@0x2a0010   4       third_party/fft_float.cc
+13)  35900590 (82.0%) t@0x2a0010   4       third_party/fft_float.cc
              BarAlias
-14)     75576 (0.2%)  t@0x2a0020   28      third_party/container.c
+14)  35900618 (82.0%) t@0x2a0020   28      third_party/container.c
              blink::ContiguousContainerBase::ContiguousContainerBase
-15)     79616 (0.2%)  t@0x2a1000   4040    {no path}
-             ** symbol gap 1
-16)     79710 (0.2%)  t@0x2a1000   94      third_party/container.c
-             blink::PaintChunker::releasePaintChunks [clone .part.1]
-17)  35900712 (82.0%) t@0x24ca628  35821002 {no path}
-             ** symbol gap 2 (end of section)
-18)  37862696 (86.5%) r@0x266e600  1961984 {no path}
-             ** merge strings
-19)  37866121 (86.5%) r@0x284d600  3425    {no path}
+15)  35900712 (82.0%) t@0x2a1000   94      third_party/container.c
+             blink::PaintChunker::releasePaintChunks
+16)  38538681 (88.0%) r@Group      2637969 {no path}
+             ** merge strings (count=2)
+17)  38542106 (88.0%) r@0x284d600  3425    {no path}
              ** merge constants
-20)  37866124 (86.5%) r@0x284e364  3       {no path}
-             ** symbol gap 2
-21)  37866132 (86.5%) r@0x284e364  8       base/page_allocator.cc
-22)  37866176 (86.5%) r@0x284e370  44      base/page_allocator.cc
+18)  41828221 (95.5%) r@Group      3286115 {no path}
+             ** symbol gaps (count=2)
+19)  41828229 (95.5%) r@0x284e364  8       base/page_allocator.cc
+20)  41828273 (95.5%) r@0x284e370  44      base/page_allocator.cc
              Name
-23)  37866208 (86.5%) r@0x284e398  32      third_party/container.c
+21)  41828305 (95.5%) r@0x284e398  32      third_party/container.c
              chrome::mojom::FilePatcher::Name_
-24)  38542193 (88.0%) r@0x284e518  675985  {no path}
-             ** merge strings
-25)  38542248 (88.0%) r@0x28f3450  55      third_party/paint.cc
+22)  41828360 (95.5%) r@0x28f3450  55      third_party/paint.cc
              kAnimationFrameTimeHistogramClassPath
-26)  38542252 (88.0%) r@0x28f3480  4       third_party/paint.cc
+23)  41828364 (95.5%) r@0x28f3480  4       third_party/paint.cc
              blink::CSSValueKeywordsHash::findValueImpl::value_word_list
-27)  41828364 (95.5%) r@0x2c158e4  3286112 {no path}
-             ** symbol gap 3 (end of section)
-28)  41828420 (95.5%) d@0x2c176f0  56      third_party/icu/ucnv_ext.c
+24)  41828420 (95.5%) d@0x2c176f0  56      third_party/icu/ucnv_ext.c
              ChromeMainDelegate [vtable]
-29)  41828444 (95.5%) d@0x2c17728  24      third_party/icu/ucnv_ext.c
+25)  41828444 (95.5%) d@0x2c17728  24      third_party/icu/ucnv_ext.c
              chrome::mojom::FieldTrialRecorder [vtable]
-30)  42618348 (97.3%) d@0x2c17740  789904  third_party/container.c
+26)  42618348 (97.3%) d@0x2c17740  789904  third_party/container.c
              chrome::mojom::FieldTrialRecorderProxy [vtable]
-31)  42618380 (97.3%) d@0x2cd84e0  32      third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
+27)  42618380 (97.3%) d@0x2cd84e0  32      third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
              .Lswitch.table.45
-32)  42618388 (97.3%) d@0x2cd84f0  8       third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
+28)  42618388 (97.3%) d@0x2cd84f0  8       third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              kSystemClassPrefixes
-33)  42618444 (97.3%) d@0x2cd8500  56      third_party/paint.cc
+29)  42618444 (97.3%) d@0x2cd8500  56      third_party/paint.cc
              ChromeMainDelegateAndroid [vtable]
-34)  42618468 (97.3%) d@0x2cd8538  24      base/page_allocator.cc
+30)  42618468 (97.3%) d@0x2cd8538  24      base/page_allocator.cc
              mojo::MessageReceiver [vtable]
-35)  42618480 (97.3%) d@0x2cd8550  12      base/page_allocator.cc
+31)  42618480 (97.3%) d@0x2cd8550  12      base/page_allocator.cc
              kMethodsAnimationFrameTimeHistogram
-36)  43683612 (99.8%) d@0x2ddc608  1065132 {no path}
-             ** symbol gap 3 (end of section)
-37)  43683616 (99.8%) d@0x2de7000  4       base/page_allocator.cc
+32)  43683612 (99.8%) d@0x2ddc608  1065132 {no path}
+             ** symbol gap 0 (end of section)
+33)  43683616 (99.8%) d@0x2de7000  4       base/page_allocator.cc
              google::protobuf::internal::pLinuxKernelCmpxchg
-38)  43683620 (99.8%) d@0x2de7004  4       third_party/container.c
+34)  43683620 (99.8%) d@0x2de7004  4       third_party/container.c
              google::protobuf::internal::pLinuxKernelMemoryBarrier
-39)  43683772 (99.8%) d@0x2de7008  152     third_party/container.c
+35)  43683772 (99.8%) d@0x2de7008  152     third_party/container.c
              base::android::kBaseRegisteredMethods
-40)  43683776 (99.8%) d@0x2de70a0  4       third_party/container.c
+36)  43683776 (99.8%) d@0x2de70a0  4       third_party/container.c
              base::android::g_renderer_histogram_code
-41)  43683780 (99.8%) d@0x2de70a4  4       third_party/container.c
+37)  43683780 (99.8%) d@0x2de70a4  4       third_party/container.c
              base::android::g_library_version_number
-42)  43785380 (100.0%) d@0x2dffd88  101600  {no path}
-             ** symbol gap 3 (end of section)
-43)  43785380 (100.0%) b@0x0        262144  third_party/fft_float.cc
+38)  43785380 (100.0%) d@0x2dffd88  101600  {no path}
+             ** symbol gap 0 (end of section)
+39)  43785380 (100.0%) b@0x0        262144  third_party/fft_float.cc
              ff_cos_131072
-44)  43785380 (100.0%) b@0x0        131072  third_party/fft_fixed.cc
+40)  43785380 (100.0%) b@0x0        131072  third_party/fft_fixed.cc
              ff_cos_131072_fixed
-45)  43785380 (100.0%) b@0x0        131072  third_party/fft_float.cc
+41)  43785380 (100.0%) b@0x0        131072  third_party/fft_float.cc
              ff_cos_65536
-46)  43785380 (100.0%) b@0x2dffda0  28      third_party/icu/ucnv_ext.c
+42)  43785380 (100.0%) b@0x2dffda0  28      third_party/icu/ucnv_ext.c
              g_chrome_content_browser_client
-47)  43785380 (100.0%) b@0x2dffe80  200     third_party/icu/ucnv_ext.c
+43)  43785380 (100.0%) b@0x2dffe80  200     third_party/icu/ucnv_ext.c
              SaveHistogram::atomic_histogram_pointer
-48)  43785380 (100.0%) b@0x2dffe84  4       third_party/icu/ucnv_ext.c
+44)  43785380 (100.0%) b@0x2dffe84  4       third_party/icu/ucnv_ext.c
              g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
index 44930f1d..b6b6070 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden
@@ -38,142 +38,144 @@
     .strtab: 0 bytes (0 bytes)
     .symtab: 0 bytes (0 bytes)
 
-2 symbols added (+), 1 changed (~), 3 removed (-), 35 unchanged (=)
-0 object files added, 0 removed
+0 symbols added (+), 1 changed (~), 0 removed (-), 40 unchanged (=)
+0 paths added, 0 removed, 1 changed
+Changed files:
+  base/page_allocator.cc
 
-Showing 41 symbols (41 unique) with total pss: 82 bytes
-.text=82 bytes   .rodata=0 bytes    .data*=0 bytes    .bss=-36 bytes  total=82 bytes
-Number of object files: 9
+Showing 41 symbols (41 unique) with total pss: 10 bytes
+.text=10 bytes   .rodata=0 bytes    .data*=0 bytes    .bss=0 bytes    total=10 bytes
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
-+ 0)         56 (68.3%) t@0x28d910   pss=56  padding=0  size_without_padding=56
-               source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-               flags={startup}  name=_GLOBAL__sub_I_bbr_sender.cc
-+ 1)         72 (87.8%) t@0x28d900   pss=16  padding=0  size_without_padding=16
-               source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-               flags={startup}  name=_GLOBAL__sub_I_page_allocator.cc
-~ 2)         82 (100.0%) t@0x28d964   pss=10  padding=0  size_without_padding=10
+~ 0)         10 (100.0%) t@0x28d964   pss=10  padding=0  size_without_padding=10
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=extFromUUseMapping
                     full_name=extFromUUseMapping(signed char, unsigned int, int)
-= 3)         82 (100.0%) r@0x284e364  pss=0  padding=0  size_without_padding=0
+= 1)         10 (100.0%) r@0x284e364  pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-= 4)         82 (100.0%) r@0x284d600  pss=0  padding=0  size_without_padding=0
+= 2)         10 (100.0%) r@0x284d600  pss=0  padding=0  size_without_padding=0
                source_path= 	object_path=
                flags={}  name=** merge constants
-= 5)         82 (100.0%) r@Group      pss=0  padding=0  size_without_padding=0  count=2
+= 3)         10 (100.0%) r@Group      pss=0  padding=0  size_without_padding=0  count=2
                source_path= 	object_path=
                flags={}  name=** merge strings
-= 6)         82 (100.0%) d@0x2ddc608  pss=0  padding=0  size_without_padding=0
+= 4)         10 (100.0%) d@0x2ddc608  pss=0  padding=0  size_without_padding=0
                source_path= 	object_path=
-               flags={}  name=** symbol gap 3 (end of section)
-= 7)         82 (100.0%) d@0x2dffd88  pss=0  padding=0  size_without_padding=0
+               flags={}  name=** symbol gap 0 (end of section)
+= 5)         10 (100.0%) d@0x2dffd88  pss=0  padding=0  size_without_padding=0
                source_path= 	object_path=
-               flags={}  name=** symbol gap 3 (end of section)
-= 8)         82 (100.0%) t@Group      pss=0  padding=0  size_without_padding=0  count=3
+               flags={}  name=** symbol gap 0 (end of section)
+= 6)         10 (100.0%) t@Group      pss=0  padding=0  size_without_padding=0  count=3
                source_path= 	object_path=
                flags={}  name=** symbol gaps
-= 9)         82 (100.0%) r@Group      pss=0  padding=0  size_without_padding=0  count=2
+= 7)         10 (100.0%) r@Group      pss=0  padding=0  size_without_padding=0  count=2
                source_path= 	object_path=
                flags={}  name=** symbol gaps
-= 10)        82 (100.0%) d@0x2cd84e0  pss=0  padding=0  size_without_padding=0
+= 8)         10 (100.0%) d@0x2cd84e0  pss=0  padding=0  size_without_padding=0
                source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
                flags={}  name=.Lswitch.table.45
-= 11)        82 (100.0%) d@0x2c176f0  pss=0  padding=0  size_without_padding=0
+= 9)         10 (100.0%) d@0x2c176f0  pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={gen}  name=ChromeMainDelegate [vtable]
-= 12)        82 (100.0%) d@0x2cd8500  pss=0  padding=0  size_without_padding=0
+= 10)        10 (100.0%) d@0x2cd8500  pss=0  padding=0  size_without_padding=0
                source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
                flags={}  name=ChromeMainDelegateAndroid [vtable]
-= 13)        82 (100.0%) r@0x284e370  pss=0  padding=0  size_without_padding=0
+= 11)        10 (100.0%) r@0x284e370  pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=Name
-= 14)        82 (100.0%) t@0x28f1c8   pss=0  padding=0  size_without_padding=0
+= 12)        10 (100.0%) t@0x28f1c8   pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={startup,gen}  name=_GLOBAL__sub_I_SkDeviceProfile.cpp
-= 15)        82 (100.0%) t@0x28d948   pss=0  padding=0  size_without_padding=0
+= 13)        10 (100.0%) t@0x28d910   pss=0  padding=0  size_without_padding=0
+               source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+               flags={startup}  name=_GLOBAL__sub_I_bbr_sender.cc
+= 14)        10 (100.0%) t@0x28d948   pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={startup}  name=_GLOBAL__sub_I_pacing_sender.cc
-= 16)        82 (100.0%) d@0x2de70a4  pss=0  padding=0  size_without_padding=0
+= 15)        10 (100.0%) t@0x28d900   pss=0  padding=0  size_without_padding=0
+               source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+               flags={startup}  name=_GLOBAL__sub_I_page_allocator.cc
+= 16)        10 (100.0%) d@0x2de70a4  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={anon,rel.loc}  name=base::android::g_library_version_number
-= 17)        82 (100.0%) d@0x2de70a0  pss=0  padding=0  size_without_padding=0
+= 17)        10 (100.0%) d@0x2de70a0  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={anon}  name=base::android::g_renderer_histogram_code
-= 18)        82 (100.0%) d@0x2de7008  pss=0  padding=0  size_without_padding=0
+= 18)        10 (100.0%) d@0x2de7008  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={rel}  name=base::android::kBaseRegisteredMethods
-= 19)        82 (100.0%) r@0x28f3480  pss=0  padding=0  size_without_padding=0
+= 19)        10 (100.0%) r@0x28f3480  pss=0  padding=0  size_without_padding=0
                source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
                flags={anon}  name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list
                     full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list
-= 20)        82 (100.0%) t@0x2a0020   pss=0  padding=0  size_without_padding=0
+= 20)        10 (100.0%) t@0x2a0020   pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={}  name=blink::ContiguousContainerBase::ContiguousContainerBase
                     full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&)
-= 21)        82 (100.0%) t@Group      pss=0  padding=0  size_without_padding=0  count=2
+= 21)        10 (100.0%) t@Group      pss=0  padding=0  size_without_padding=0  count=2
                source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
                flags={}  name=blink::ContiguousContainerBase::shrinkToFit
                     full_name=blink::ContiguousContainerBase::shrinkToFit()
-= 22)        82 (100.0%) t@0x2a1000   pss=0  padding=0  size_without_padding=0
+= 22)        10 (100.0%) t@0x2a1000   pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
-               flags={anon}  name=blink::PaintChunker::releasePaintChunks [clone .part.1]
-                    full_name=blink::PaintChunker::releasePaintChunks() [clone .part.1]
-= 23)        82 (100.0%) d@0x2c17728  pss=0  padding=0  size_without_padding=0
+               flags={anon,clone}  name=blink::PaintChunker::releasePaintChunks
+                    full_name=blink::PaintChunker::releasePaintChunks()
+= 23)        10 (100.0%) d@0x2c17728  pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={gen}  name=chrome::mojom::FieldTrialRecorder [vtable]
-= 24)        82 (100.0%) d@0x2c17740  pss=0  padding=0  size_without_padding=0
+= 24)        10 (100.0%) d@0x2c17740  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={}  name=chrome::mojom::FieldTrialRecorderProxy [vtable]
-= 25)        82 (100.0%) r@0x284e398  pss=0  padding=0  size_without_padding=0
+= 25)        10 (100.0%) r@0x284e398  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={}  name=chrome::mojom::FilePatcher::Name_
-= 26)        82 (100.0%) t@0x28d98a   pss=0  padding=0  size_without_padding=0
+= 26)        10 (100.0%) t@0x28d98a   pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=extFromUUseMapping
                     full_name=extFromUUseMapping(aj, int)
-= 27)        82 (100.0%) t@0x28f1e0   pss=0  padding=0  size_without_padding=0
+= 27)        10 (100.0%) t@0x28f1e0   pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={unlikely,gen}  name=foo_bar
-= 28)        82 (100.0%) d@0x2de7000  pss=0  padding=0  size_without_padding=0
+= 28)        10 (100.0%) d@0x2de7000  pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=google::protobuf::internal::pLinuxKernelCmpxchg
-= 29)        82 (100.0%) d@0x2de7004  pss=0  padding=0  size_without_padding=0
+= 29)        10 (100.0%) d@0x2de7004  pss=0  padding=0  size_without_padding=0
                source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
                flags={}  name=google::protobuf::internal::pLinuxKernelMemoryBarrier
-= 30)        82 (100.0%) r@0x28f3450  pss=0  padding=0  size_without_padding=0
+= 30)        10 (100.0%) r@0x28f3450  pss=0  padding=0  size_without_padding=0
                source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
                flags={anon}  name=kAnimationFrameTimeHistogramClassPath
-= 31)        82 (100.0%) d@0x2cd8550  pss=0  padding=0  size_without_padding=0
+= 31)        10 (100.0%) d@0x2cd8550  pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=kMethodsAnimationFrameTimeHistogram
-= 32)        82 (100.0%) d@0x2cd84f0  pss=0  padding=0  size_without_padding=0
+= 32)        10 (100.0%) d@0x2cd84f0  pss=0  padding=0  size_without_padding=0
                source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
                flags={anon}  name=kSystemClassPrefixes
-= 33)        82 (100.0%) d@0x2cd8538  pss=0  padding=0  size_without_padding=0
+= 33)        10 (100.0%) d@0x2cd8538  pss=0  padding=0  size_without_padding=0
                source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
                flags={}  name=mojo::MessageReceiver [vtable]
-= 34)        82 (100.0%) t@0x28f000   pss=0  padding=0  size_without_padding=0
+= 34)        10 (100.0%) t@0x28f000   pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={gen}  name=ucnv_extMatchFromU
                     full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char)
-- 35)        82 (100.0%) b@0x2dffda0  pss=-28  padding=0  size_without_padding=-28
-               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
-               flags={gen}  name=g_chrome_content_browser_client
-- 36)        82 (100.0%) b@0x2dffe80  pss=-4  padding=-196  size_without_padding=192
+= 35)        10 (100.0%) b@0x2dffe80  pss=0  padding=0  size_without_padding=0
                source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
                flags={gen}  name=SaveHistogram::atomic_histogram_pointer
                     full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
-- 37)        82 (100.0%) b@0x2dffe84  pss=-4  padding=0  size_without_padding=-4
-               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
-               flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
-= 38)        82 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
+= 36)        10 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
                source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
                flags={}  name=ff_cos_131072
-= 39)        82 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
+= 37)        10 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
                source_path=third_party/fft_fixed.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o
                flags={}  name=ff_cos_131072_fixed
-= 40)        82 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
+= 38)        10 (100.0%) b@0x0        pss=0  padding=0  size_without_padding=0
                source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
                flags={}  name=ff_cos_65536
+= 39)        10 (100.0%) b@0x2dffe84  pss=0  padding=0  size_without_padding=0
+               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+               flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
+= 40)        10 (100.0%) b@0x2dffda0  pss=0  padding=0  size_without_padding=0
+               source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+               flags={gen}  name=g_chrome_content_browser_client
diff --git a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
index 086a841..a780240 100644
--- a/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
+++ b/tools/binary_size/libsupersize/testdata/Diff_NullDiff.golden
@@ -18,12 +18,12 @@
     .rodata: 0 bytes (0 bytes) (0.0%)
     .text: 0 bytes (0 bytes) (0.0%)
 
-0 symbols added (+), 0 changed (~), 0 removed (-), 44 unchanged (not shown)
-0 object files added, 0 removed
+0 symbols added (+), 0 changed (~), 0 removed (-), 45 unchanged (not shown)
+0 paths added, 0 removed, 0 changed
 
 Showing 0 symbols (0 unique) with total pss: 0 bytes
 .text=0 bytes    .rodata=0 bytes    .data*=0 bytes    .bss=0 bytes    total=0 bytes
-Number of object files: 0
+Number of unique paths: 0
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden
index f372b1dd..de96cdd 100644
--- a/tools/binary_size/libsupersize/testdata/FullDescription.golden
+++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -57,9 +57,173 @@
 * Contains 5 aliases, mapped to 2 unique addresses (60 bytes)
 * 1 symbols have shared ownership (12 bytes)
 
-Showing 44 symbols (43 unique) with total pss: 43785380 bytes
+Showing 49 symbols (46 unique) with total pss: 43785380 bytes
 .text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
+Number of unique paths: 9
+
+Index, Running Total, Section@Address, PSS
+------------------------------------------------------------
+0)         16 (0.0%)  t@0x28d900   pss=16  padding=0  size_without_padding=16
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={startup}  name=_GLOBAL__sub_I_page_allocator.cc
+1)         72 (0.0%)  t@0x28d910   pss=56  padding=0  size_without_padding=56
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={startup}  name=_GLOBAL__sub_I_bbr_sender.cc
+2)        100 (0.0%)  t@0x28d948   pss=28  padding=0  size_without_padding=28
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={startup}  name=_GLOBAL__sub_I_pacing_sender.cc
+3)        138 (0.0%)  t@0x28d964   pss=38  padding=0  size_without_padding=38
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=extFromUUseMapping
+                  full_name=extFromUUseMapping(signed char, unsigned int, int)
+4)        170 (0.0%)  t@0x28d98a   pss=32  padding=0  size_without_padding=32
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=extFromUUseMapping
+                  full_name=extFromUUseMapping(aj, int)
+5)       5888 (0.0%)  t@0x28f000   pss=5718  padding=5718  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 0
+6)       6336 (0.0%)  t@0x28f000   pss=448  padding=0  size_without_padding=448
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen}  name=ucnv_extMatchFromU
+                  full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char)
+7)       6364 (0.0%)  t@0x28f1c8   pss=28  padding=8  size_without_padding=20
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={startup,gen}  name=_GLOBAL__sub_I_SkDeviceProfile.cpp
+8)      75488 (0.2%)  t@0x28f1e0   pss=69124  padding=4  size_without_padding=69120
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={unlikely,gen}  name=foo_bar
+9)      75512 (0.2%)  t@0x2a0000   pss=24  padding=32  size_without_padding=16
+             source_path= 	object_path=
+             flags={2 aliases}  name=blink::ContiguousContainerBase::shrinkToFit
+                  full_name=blink::ContiguousContainerBase::shrinkToFit()
+10)     75536 (0.2%)  t@0x2a0000   pss=24  padding=32  size_without_padding=16
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen,2 aliases}  name=BazAlias
+                  full_name=BazAlias(bool)
+11)     75540 (0.2%)  t@0x2a0010   pss=4  padding=0  size_without_padding=12
+             source_path=third_party/{shared}/2 	object_path=third_party/{shared}/2
+             flags={clone,3 aliases}  name=blink::ContiguousContainerBase::shrinkToFit
+                  full_name=blink::ContiguousContainerBase::shrinkToFit()
+12)     75544 (0.2%)  t@0x2a0010   pss=4  padding=0  size_without_padding=12
+             source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
+             flags={3 aliases}  name=FooAlias
+                  full_name=FooAlias()
+13)     75548 (0.2%)  t@0x2a0010   pss=4  padding=0  size_without_padding=12
+             source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
+             flags={3 aliases}  name=BarAlias
+                  full_name=BarAlias()
+14)     75576 (0.2%)  t@0x2a0020   pss=28  padding=4  size_without_padding=24
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={}  name=blink::ContiguousContainerBase::ContiguousContainerBase
+                  full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&)
+15)     79616 (0.2%)  t@0x2a1000   pss=4040  padding=4040  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 1
+16)     79710 (0.2%)  t@0x2a1000   pss=94  padding=0  size_without_padding=94
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={anon,clone}  name=blink::PaintChunker::releasePaintChunks
+                  full_name=blink::PaintChunker::releasePaintChunks()
+17)  35900712 (82.0%) t@0x24ca628  pss=35821002  padding=35821002  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 2 (end of section)
+18)  37862696 (86.5%) r@0x266e600  pss=1961984  padding=0  size_without_padding=1961984
+             source_path= 	object_path=
+             flags={}  name=** merge strings
+19)  37866121 (86.5%) r@0x284d600  pss=3425  padding=0  size_without_padding=3425
+             source_path= 	object_path=
+             flags={}  name=** merge constants
+20)  37866124 (86.5%) r@0x284e364  pss=3  padding=3  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 0
+21)  37866132 (86.5%) r@0x284e364  pss=8  padding=0  size_without_padding=8
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+22)  37866176 (86.5%) r@0x284e370  pss=44  padding=4  size_without_padding=40
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=Name
+23)  37866208 (86.5%) r@0x284e398  pss=32  padding=0  size_without_padding=32
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={}  name=chrome::mojom::FilePatcher::Name_
+24)  38542193 (88.0%) r@0x284e518  pss=675985  padding=352  size_without_padding=675633
+             source_path= 	object_path=
+             flags={}  name=** merge strings
+25)  38542248 (88.0%) r@0x28f3450  pss=55  padding=7  size_without_padding=48
+             source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
+             flags={anon}  name=kAnimationFrameTimeHistogramClassPath
+26)  38542252 (88.0%) r@0x28f3480  pss=4  padding=0  size_without_padding=4
+             source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
+             flags={anon}  name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list
+                  full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list
+27)  41828364 (95.5%) r@0x2c158e4  pss=3286112  padding=3286112  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 1 (end of section)
+28)  41828420 (95.5%) d@0x2c176f0  pss=56  padding=0  size_without_padding=56
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen}  name=ChromeMainDelegate [vtable]
+29)  41828444 (95.5%) d@0x2c17728  pss=24  padding=0  size_without_padding=24
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen}  name=chrome::mojom::FieldTrialRecorder [vtable]
+30)  42618348 (97.3%) d@0x2c17740  pss=789904  padding=0  size_without_padding=789904
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={}  name=chrome::mojom::FieldTrialRecorderProxy [vtable]
+31)  42618380 (97.3%) d@0x2cd84e0  pss=32  padding=16  size_without_padding=16
+             source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
+             flags={}  name=.Lswitch.table.45
+32)  42618388 (97.3%) d@0x2cd84f0  pss=8  padding=0  size_without_padding=8
+             source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
+             flags={anon}  name=kSystemClassPrefixes
+33)  42618444 (97.3%) d@0x2cd8500  pss=56  padding=0  size_without_padding=56
+             source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
+             flags={}  name=ChromeMainDelegateAndroid [vtable]
+34)  42618468 (97.3%) d@0x2cd8538  pss=24  padding=0  size_without_padding=24
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=mojo::MessageReceiver [vtable]
+35)  42618480 (97.3%) d@0x2cd8550  pss=12  padding=0  size_without_padding=12
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=kMethodsAnimationFrameTimeHistogram
+36)  43683612 (99.8%) d@0x2ddc608  pss=1065132  padding=1065132  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 0 (end of section)
+37)  43683616 (99.8%) d@0x2de7000  pss=4  padding=0  size_without_padding=4
+             source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
+             flags={}  name=google::protobuf::internal::pLinuxKernelCmpxchg
+38)  43683620 (99.8%) d@0x2de7004  pss=4  padding=0  size_without_padding=4
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={}  name=google::protobuf::internal::pLinuxKernelMemoryBarrier
+39)  43683772 (99.8%) d@0x2de7008  pss=152  padding=0  size_without_padding=152
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={rel}  name=base::android::kBaseRegisteredMethods
+40)  43683776 (99.8%) d@0x2de70a0  pss=4  padding=0  size_without_padding=4
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={anon}  name=base::android::g_renderer_histogram_code
+41)  43683780 (99.8%) d@0x2de70a4  pss=4  padding=0  size_without_padding=4
+             source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
+             flags={anon,rel.loc}  name=base::android::g_library_version_number
+42)  43785380 (100.0%) d@0x2dffd88  pss=101600  padding=101600  size_without_padding=0
+             source_path= 	object_path=
+             flags={}  name=** symbol gap 0 (end of section)
+43)  43785380 (100.0%) b@0x0        pss=262144  padding=0  size_without_padding=262144
+             source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
+             flags={}  name=ff_cos_131072
+44)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
+             source_path=third_party/fft_fixed.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o
+             flags={}  name=ff_cos_131072_fixed
+45)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
+             source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
+             flags={}  name=ff_cos_65536
+46)  43785380 (100.0%) b@0x2dffda0  pss=28  padding=0  size_without_padding=28
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen}  name=g_chrome_content_browser_client
+47)  43785380 (100.0%) b@0x2dffe80  pss=200  padding=196  size_without_padding=4
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={gen}  name=SaveHistogram::atomic_histogram_pointer
+                  full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
+48)  43785380 (100.0%) b@0x2dffe84  pss=4  padding=0  size_without_padding=4
+             source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
+             flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
+Showing 45 symbols (42 unique) with total pss: 43785380 bytes
+.text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
@@ -102,39 +266,35 @@
 8)   35900530 (82.0%) t@0x28f1e0   pss=69124  padding=4  size_without_padding=69120
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={unlikely,gen}  name=foo_bar
-9)   35900558 (82.0%) t@Group      pss=28  padding=32  size_without_padding=28  count=2
+9)   35900554 (82.0%) t@0x2a0000   pss=24  padding=32  size_without_padding=16
              source_path= 	object_path=
-             flags={}  name=blink::ContiguousContainerBase::shrinkToFit
+             flags={2 aliases}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-> 0)         24 (85.7%) t@0x2a0000   pss=24  padding=32  size_without_padding=16
-               source_path= 	object_path=
-               flags={2 aliases}  name=blink::ContiguousContainerBase::shrinkToFit
-                    full_name=blink::ContiguousContainerBase::shrinkToFit()
-> 1)         28 (100.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
-               source_path=third_party/{shared}/2 	object_path=third_party/{shared}/2
-               flags={3 aliases}  name=blink::ContiguousContainerBase::shrinkToFit [clone .part.1234] [clone .isra.2]
-                    full_name=blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2]
-10)  35900582 (82.0%) t@0x2a0000   pss=24  padding=32  size_without_padding=16
+10)  35900578 (82.0%) t@0x2a0000   pss=24  padding=32  size_without_padding=16
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen,2 aliases}  name=BazAlias
                   full_name=BazAlias(bool)
-11)  35900586 (82.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
+11)  35900582 (82.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
+             source_path=third_party/{shared}/2 	object_path=third_party/{shared}/2
+             flags={clone,3 aliases}  name=blink::ContiguousContainerBase::shrinkToFit
+                  full_name=blink::ContiguousContainerBase::shrinkToFit()
+12)  35900586 (82.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={3 aliases}  name=FooAlias
                   full_name=FooAlias()
-12)  35900590 (82.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
+13)  35900590 (82.0%) t@0x2a0010   pss=4  padding=0  size_without_padding=12
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={3 aliases}  name=BarAlias
                   full_name=BarAlias()
-13)  35900618 (82.0%) t@0x2a0020   pss=28  padding=4  size_without_padding=24
+14)  35900618 (82.0%) t@0x2a0020   pss=28  padding=4  size_without_padding=24
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={}  name=blink::ContiguousContainerBase::ContiguousContainerBase
                   full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&)
-14)  35900712 (82.0%) t@0x2a1000   pss=94  padding=0  size_without_padding=94
+15)  35900712 (82.0%) t@0x2a1000   pss=94  padding=0  size_without_padding=94
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
-             flags={anon}  name=blink::PaintChunker::releasePaintChunks [clone .part.1]
-                  full_name=blink::PaintChunker::releasePaintChunks() [clone .part.1]
-15)  38538681 (88.0%) r@Group      pss=2637969  padding=352  size_without_padding=2637617  count=2
+             flags={anon,clone}  name=blink::PaintChunker::releasePaintChunks
+                  full_name=blink::PaintChunker::releasePaintChunks()
+16)  38538681 (88.0%) r@Group      pss=2637969  padding=352  size_without_padding=2637617  count=2
              source_path= 	object_path=
              flags={}  name=** merge strings
 > 0)    1961984 (74.4%) r@0x266e600  pss=1961984  padding=0  size_without_padding=1961984
@@ -143,94 +303,94 @@
 > 1)    2637969 (100.0%) r@0x284e518  pss=675985  padding=352  size_without_padding=675633
                source_path= 	object_path=
                flags={}  name=** merge strings
-16)  38542106 (88.0%) r@0x284d600  pss=3425  padding=0  size_without_padding=3425
+17)  38542106 (88.0%) r@0x284d600  pss=3425  padding=0  size_without_padding=3425
              source_path= 	object_path=
              flags={}  name=** merge constants
-17)  41828221 (95.5%) r@Group      pss=3286115  padding=3286115  size_without_padding=0  count=2
+18)  41828221 (95.5%) r@Group      pss=3286115  padding=3286115  size_without_padding=0  count=2
              source_path= 	object_path=
              flags={}  name=** symbol gaps
 > 0)          3 (0.0%)  r@0x284e364  pss=3  padding=3  size_without_padding=0
                source_path= 	object_path=
-               flags={}  name=** symbol gap 2
+               flags={}  name=** symbol gap 0
 > 1)    3286115 (100.0%) r@0x2c158e4  pss=3286112  padding=3286112  size_without_padding=0
                source_path= 	object_path=
-               flags={}  name=** symbol gap 3 (end of section)
-18)  41828229 (95.5%) r@0x284e364  pss=8  padding=0  size_without_padding=8
+               flags={}  name=** symbol gap 1 (end of section)
+19)  41828229 (95.5%) r@0x284e364  pss=8  padding=0  size_without_padding=8
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-19)  41828273 (95.5%) r@0x284e370  pss=44  padding=4  size_without_padding=40
+20)  41828273 (95.5%) r@0x284e370  pss=44  padding=4  size_without_padding=40
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=Name
-20)  41828305 (95.5%) r@0x284e398  pss=32  padding=0  size_without_padding=32
+21)  41828305 (95.5%) r@0x284e398  pss=32  padding=0  size_without_padding=32
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={}  name=chrome::mojom::FilePatcher::Name_
-21)  41828360 (95.5%) r@0x28f3450  pss=55  padding=7  size_without_padding=48
+22)  41828360 (95.5%) r@0x28f3450  pss=55  padding=7  size_without_padding=48
              source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
              flags={anon}  name=kAnimationFrameTimeHistogramClassPath
-22)  41828364 (95.5%) r@0x28f3480  pss=4  padding=0  size_without_padding=4
+23)  41828364 (95.5%) r@0x28f3480  pss=4  padding=0  size_without_padding=4
              source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
              flags={anon}  name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list
                   full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list
-23)  41828420 (95.5%) d@0x2c176f0  pss=56  padding=0  size_without_padding=56
+24)  41828420 (95.5%) d@0x2c176f0  pss=56  padding=0  size_without_padding=56
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=ChromeMainDelegate [vtable]
-24)  41828444 (95.5%) d@0x2c17728  pss=24  padding=0  size_without_padding=24
+25)  41828444 (95.5%) d@0x2c17728  pss=24  padding=0  size_without_padding=24
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=chrome::mojom::FieldTrialRecorder [vtable]
-25)  42618348 (97.3%) d@0x2c17740  pss=789904  padding=0  size_without_padding=789904
+26)  42618348 (97.3%) d@0x2c17740  pss=789904  padding=0  size_without_padding=789904
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={}  name=chrome::mojom::FieldTrialRecorderProxy [vtable]
-26)  42618380 (97.3%) d@0x2cd84e0  pss=32  padding=16  size_without_padding=16
+27)  42618380 (97.3%) d@0x2cd84e0  pss=32  padding=16  size_without_padding=16
              source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
              flags={}  name=.Lswitch.table.45
-27)  42618388 (97.3%) d@0x2cd84f0  pss=8  padding=0  size_without_padding=8
+28)  42618388 (97.3%) d@0x2cd84f0  pss=8  padding=0  size_without_padding=8
              source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              flags={anon}  name=kSystemClassPrefixes
-28)  42618444 (97.3%) d@0x2cd8500  pss=56  padding=0  size_without_padding=56
+29)  42618444 (97.3%) d@0x2cd8500  pss=56  padding=0  size_without_padding=56
              source_path=third_party/paint.cc 	object_path=third_party/WebKit.a/PaintChunker.o
              flags={}  name=ChromeMainDelegateAndroid [vtable]
-29)  42618468 (97.3%) d@0x2cd8538  pss=24  padding=0  size_without_padding=24
+30)  42618468 (97.3%) d@0x2cd8538  pss=24  padding=0  size_without_padding=24
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=mojo::MessageReceiver [vtable]
-30)  42618480 (97.3%) d@0x2cd8550  pss=12  padding=0  size_without_padding=12
+31)  42618480 (97.3%) d@0x2cd8550  pss=12  padding=0  size_without_padding=12
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=kMethodsAnimationFrameTimeHistogram
-31)  43683612 (99.8%) d@0x2ddc608  pss=1065132  padding=1065132  size_without_padding=0
+32)  43683612 (99.8%) d@0x2ddc608  pss=1065132  padding=1065132  size_without_padding=0
              source_path= 	object_path=
-             flags={}  name=** symbol gap 3 (end of section)
-32)  43683616 (99.8%) d@0x2de7000  pss=4  padding=0  size_without_padding=4
+             flags={}  name=** symbol gap 0 (end of section)
+33)  43683616 (99.8%) d@0x2de7000  pss=4  padding=0  size_without_padding=4
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=google::protobuf::internal::pLinuxKernelCmpxchg
-33)  43683620 (99.8%) d@0x2de7004  pss=4  padding=0  size_without_padding=4
+34)  43683620 (99.8%) d@0x2de7004  pss=4  padding=0  size_without_padding=4
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={}  name=google::protobuf::internal::pLinuxKernelMemoryBarrier
-34)  43683772 (99.8%) d@0x2de7008  pss=152  padding=0  size_without_padding=152
+35)  43683772 (99.8%) d@0x2de7008  pss=152  padding=0  size_without_padding=152
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={rel}  name=base::android::kBaseRegisteredMethods
-35)  43683776 (99.8%) d@0x2de70a0  pss=4  padding=0  size_without_padding=4
+36)  43683776 (99.8%) d@0x2de70a0  pss=4  padding=0  size_without_padding=4
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={anon}  name=base::android::g_renderer_histogram_code
-36)  43683780 (99.8%) d@0x2de70a4  pss=4  padding=0  size_without_padding=4
+37)  43683780 (99.8%) d@0x2de70a4  pss=4  padding=0  size_without_padding=4
              source_path=third_party/container.c 	object_path=third_party/WebKit.a/ContiguousContainer.o
              flags={anon,rel.loc}  name=base::android::g_library_version_number
-37)  43785380 (100.0%) d@0x2dffd88  pss=101600  padding=101600  size_without_padding=0
+38)  43785380 (100.0%) d@0x2dffd88  pss=101600  padding=101600  size_without_padding=0
              source_path= 	object_path=
-             flags={}  name=** symbol gap 3 (end of section)
-38)  43785380 (100.0%) b@0x0        pss=262144  padding=0  size_without_padding=262144
+             flags={}  name=** symbol gap 0 (end of section)
+39)  43785380 (100.0%) b@0x0        pss=262144  padding=0  size_without_padding=262144
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_131072
-39)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
+40)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
              source_path=third_party/fft_fixed.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o
              flags={}  name=ff_cos_131072_fixed
-40)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
+41)  43785380 (100.0%) b@0x0        pss=131072  padding=0  size_without_padding=131072
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_65536
-41)  43785380 (100.0%) b@0x2dffda0  pss=28  padding=0  size_without_padding=28
+42)  43785380 (100.0%) b@0x2dffda0  pss=28  padding=0  size_without_padding=28
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=g_chrome_content_browser_client
-42)  43785380 (100.0%) b@0x2dffe80  pss=200  padding=196  size_without_padding=4
+43)  43785380 (100.0%) b@0x2dffe80  pss=200  padding=196  size_without_padding=4
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=SaveHistogram::atomic_histogram_pointer
                   full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
-43)  43785380 (100.0%) b@0x2dffe84  pss=4  padding=0  size_without_padding=4
+44)  43785380 (100.0%) b@0x2dffe84  pss=4  padding=0  size_without_padding=4
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
index c3459e2a..f1cc453 100644
--- a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
+++ b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
@@ -1,219 +1,203 @@
 GroupedByName()
-Showing 45 symbols (45 unique) with total pss: 43785380 bytes
+Showing 41 symbols (41 unique) with total pss: 43785380 bytes
 .text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
-0)          8 (0.0%)  *@Group      8        (count=1)
-1)         64 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
-2)         64 (0.0%)  *@Group      0       ff_cos_65536 (count=1)
-3)        216 (0.0%)  *@Group      152     base::android::kBaseRegisteredMethods (count=1)
-4)        220 (0.0%)  *@Group      4       BarAlias (count=1)
-5)        224 (0.0%)  *@Group      4       blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1)
-6)        294 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
-7)        294 (0.0%)  *@Group      0       ff_cos_131072_fixed (count=1)
-8)    2638263 (6.0%)  *@Group      2637969 ** merge strings (count=2)
-9)    2638275 (6.0%)  *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
-10)   2638331 (6.0%)  *@Group      56      ChromeMainDelegate [vtable] (count=1)
-11)   2638359 (6.0%)  *@Group      28      blink::ContiguousContainerBase::ContiguousContainerBase (count=1)
-12)   2638367 (6.0%)  *@Group      8       kSystemClassPrefixes (count=1)
-13)   7091211 (16.2%) *@Group      4452844 ** symbol gap 3 (end of section) (count=3)
-14)   7091235 (16.2%) *@Group      24      blink::ContiguousContainerBase::shrinkToFit (count=1)
-15)   7160359 (16.4%) *@Group      69124   foo_bar (count=1)
-16)   7160359 (16.4%) *@Group      0       SaveHistogram::atomic_histogram_pointer (count=1)
-17)   7160453 (16.4%) *@Group      94      blink::PaintChunker::releasePaintChunks [clone .part.1] (count=1)
-18)   7160457 (16.4%) *@Group      4       base::android::g_renderer_histogram_code (count=1)
-19)   7160460 (16.4%) *@Group      3       ** symbol gap 2 (count=1)
-20)   7164500 (16.4%) *@Group      4040    ** symbol gap 1 (count=1)
-21)   7170218 (16.4%) *@Group      5718    ** symbol gap 0 (count=1)
-22)   7170218 (16.4%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
-23)   7170222 (16.4%) *@Group      4       google::protobuf::internal::pLinuxKernelCmpxchg (count=1)
-24)   7170246 (16.4%) *@Group      24      mojo::MessageReceiver [vtable] (count=1)
-25)   7170290 (16.4%) *@Group      44      Name (count=1)
-26)   7170294 (16.4%) *@Group      4       base::android::g_library_version_number (count=1)
-27)   7960198 (18.2%) *@Group      789904  chrome::mojom::FieldTrialRecorderProxy [vtable] (count=1)
-28)   7960222 (18.2%) *@Group      24      BazAlias (count=1)
-29)  43781224 (100.0%) *@Group      35821002 ** symbol gap 2 (end of section) (count=1)
-30)  43781224 (100.0%) *@Group      0       ff_cos_131072 (count=1)
-31)  43781224 (100.0%) *@Group      0       g_chrome_content_browser_client (count=1)
-32)  43781248 (100.0%) *@Group      24      chrome::mojom::FieldTrialRecorder [vtable] (count=1)
-33)  43781252 (100.0%) *@Group      4       blink::ContiguousContainerBase::shrinkToFit [clone .part.1234] [clone .isra.2] (count=1)
-34)  43784677 (100.0%) *@Group      3425    ** merge constants (count=1)
-35)  43784732 (100.0%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
-36)  43784764 (100.0%) *@Group      32      chrome::mojom::FilePatcher::Name_ (count=1)
-37)  43784792 (100.0%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-38)  43784796 (100.0%) *@Group      4       google::protobuf::internal::pLinuxKernelMemoryBarrier (count=1)
-39)  43784852 (100.0%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
-40)  43784884 (100.0%) *@Group      32      .Lswitch.table.45 (count=1)
-41)  43784888 (100.0%) *@Group      4       FooAlias (count=1)
-42)  43784904 (100.0%) *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
-43)  43785352 (100.0%) *@Group      448     ucnv_extMatchFromU (count=1)
-44)  43785380 (100.0%) *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
+0)         16 (0.0%)  *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
+1)         72 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
+2)        100 (0.0%)  *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
+3)        170 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
+4)   39117045 (89.3%) *@Group      39116875 ** symbol gaps (count=2)
+5)   39117493 (89.3%) *@Group      448     ucnv_extMatchFromU (count=1)
+6)   39117521 (89.3%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+7)   39186645 (89.5%) *@Group      69124   foo_bar (count=1)
+8)   39186673 (89.5%) *@Group      28      blink::ContiguousContainerBase::shrinkToFit (count=2)
+9)   39186697 (89.5%) *@Group      24      BazAlias (count=1)
+10)  39186701 (89.5%) *@Group      4       FooAlias (count=1)
+11)  39186705 (89.5%) *@Group      4       BarAlias (count=1)
+12)  39186733 (89.5%) *@Group      28      blink::ContiguousContainerBase::ContiguousContainerBase (count=1)
+13)  39186827 (89.5%) *@Group      94      blink::PaintChunker::releasePaintChunks (count=1)
+14)  41824796 (95.5%) *@Group      2637969 ** merge strings (count=1)
+15)  41828221 (95.5%) *@Group      3425    ** merge constants (count=1)
+16)  41828229 (95.5%) *@Group      8        (count=1)
+17)  41828273 (95.5%) *@Group      44      Name (count=1)
+18)  41828305 (95.5%) *@Group      32      chrome::mojom::FilePatcher::Name_ (count=1)
+19)  41828360 (95.5%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
+20)  41828364 (95.5%) *@Group      4       blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1)
+21)  41828420 (95.5%) *@Group      56      ChromeMainDelegate [vtable] (count=1)
+22)  41828444 (95.5%) *@Group      24      chrome::mojom::FieldTrialRecorder [vtable] (count=1)
+23)  42618348 (97.3%) *@Group      789904  chrome::mojom::FieldTrialRecorderProxy [vtable] (count=1)
+24)  42618380 (97.3%) *@Group      32      .Lswitch.table.45 (count=1)
+25)  42618388 (97.3%) *@Group      8       kSystemClassPrefixes (count=1)
+26)  42618444 (97.3%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
+27)  42618468 (97.3%) *@Group      24      mojo::MessageReceiver [vtable] (count=1)
+28)  42618480 (97.3%) *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
+29)  43785212 (100.0%) *@Group      1166732 ** symbol gap 0 (end of section) (count=2)
+30)  43785216 (100.0%) *@Group      4       google::protobuf::internal::pLinuxKernelCmpxchg (count=1)
+31)  43785220 (100.0%) *@Group      4       google::protobuf::internal::pLinuxKernelMemoryBarrier (count=1)
+32)  43785372 (100.0%) *@Group      152     base::android::kBaseRegisteredMethods (count=1)
+33)  43785376 (100.0%) *@Group      4       base::android::g_renderer_histogram_code (count=1)
+34)  43785380 (100.0%) *@Group      4       base::android::g_library_version_number (count=1)
+35)  43785380 (100.0%) *@Group      0       ff_cos_131072 (count=1)
+36)  43785380 (100.0%) *@Group      0       ff_cos_131072_fixed (count=1)
+37)  43785380 (100.0%) *@Group      0       ff_cos_65536 (count=1)
+38)  43785380 (100.0%) *@Group      0       g_chrome_content_browser_client (count=1)
+39)  43785380 (100.0%) *@Group      0       SaveHistogram::atomic_histogram_pointer (count=1)
+40)  43785380 (100.0%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
 GroupedByName(depth=1)
+Showing 33 symbols (33 unique) with total pss: 43785380 bytes
+.text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
+Number of unique paths: 9
+
+Index, Running Total, Section@Address, PSS
+------------------------------------------------------------
+0)         16 (0.0%)  *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
+1)         72 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
+2)        100 (0.0%)  *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
+3)        170 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
+4)   39117045 (89.3%) *@Group      39116875 ** symbol gaps (count=2)
+5)   39117493 (89.3%) *@Group      448     ucnv_extMatchFromU (count=1)
+6)   39117521 (89.3%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+7)   39186645 (89.5%) *@Group      69124   foo_bar (count=1)
+8)   39186799 (89.5%) *@Group      154     blink (count=5)
+9)   39186823 (89.5%) *@Group      24      BazAlias (count=1)
+10)  39186827 (89.5%) *@Group      4       FooAlias (count=1)
+11)  39186831 (89.5%) *@Group      4       BarAlias (count=1)
+12)  41824800 (95.5%) *@Group      2637969 ** merge strings (count=1)
+13)  41828225 (95.5%) *@Group      3425    ** merge constants (count=1)
+14)  41828233 (95.5%) *@Group      8        (count=1)
+15)  41828277 (95.5%) *@Group      44      Name (count=1)
+16)  42618237 (97.3%) *@Group      789960  chrome (count=3)
+17)  42618292 (97.3%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
+18)  42618348 (97.3%) *@Group      56      ChromeMainDelegate [vtable] (count=1)
+19)  42618380 (97.3%) *@Group      32      .Lswitch.table.45 (count=1)
+20)  42618388 (97.3%) *@Group      8       kSystemClassPrefixes (count=1)
+21)  42618444 (97.3%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
+22)  42618468 (97.3%) *@Group      24      mojo (count=1)
+23)  42618480 (97.3%) *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
+24)  43785212 (100.0%) *@Group      1166732 ** symbol gap 0 (end of section) (count=2)
+25)  43785220 (100.0%) *@Group      8       google (count=2)
+26)  43785380 (100.0%) *@Group      160     base (count=3)
+27)  43785380 (100.0%) *@Group      0       ff_cos_131072 (count=1)
+28)  43785380 (100.0%) *@Group      0       ff_cos_131072_fixed (count=1)
+29)  43785380 (100.0%) *@Group      0       ff_cos_65536 (count=1)
+30)  43785380 (100.0%) *@Group      0       g_chrome_content_browser_client (count=1)
+31)  43785380 (100.0%) *@Group      0       SaveHistogram (count=1)
+32)  43785380 (100.0%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
+GroupedByName(depth=-1)
 Showing 36 symbols (36 unique) with total pss: 43785380 bytes
 .text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
-0)          8 (0.0%)  *@Group      8        (count=1)
-1)         64 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
-2)         64 (0.0%)  *@Group      0       ff_cos_65536 (count=1)
-3)         72 (0.0%)  *@Group      8       google (count=2)
-4)         76 (0.0%)  *@Group      4       BarAlias (count=1)
-5)        146 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
-6)        146 (0.0%)  *@Group      0       SaveHistogram (count=1)
-7)        300 (0.0%)  *@Group      154     blink (count=5)
-8)    2638269 (6.0%)  *@Group      2637969 ** merge strings (count=2)
-9)    2638281 (6.0%)  *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
-10)   2638305 (6.0%)  *@Group      24      mojo (count=1)
-11)   2638361 (6.0%)  *@Group      56      ChromeMainDelegate [vtable] (count=1)
-12)   2638369 (6.0%)  *@Group      8       kSystemClassPrefixes (count=1)
-13)   7091213 (16.2%) *@Group      4452844 ** symbol gap 3 (end of section) (count=3)
-14)   7091213 (16.2%) *@Group      0       ff_cos_131072 (count=1)
-15)   7881173 (18.0%) *@Group      789960  chrome (count=3)
-16)   7950297 (18.2%) *@Group      69124   foo_bar (count=1)
-17)   7950297 (18.2%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
-18)   7950300 (18.2%) *@Group      3       ** symbol gap 2 (count=1)
-19)   7954340 (18.2%) *@Group      4040    ** symbol gap 1 (count=1)
-20)   7960058 (18.2%) *@Group      5718    ** symbol gap 0 (count=1)
-21)   7960102 (18.2%) *@Group      44      Name (count=1)
-22)   7960126 (18.2%) *@Group      24      BazAlias (count=1)
-23)  43781128 (100.0%) *@Group      35821002 ** symbol gap 2 (end of section) (count=1)
-24)  43781288 (100.0%) *@Group      160     base (count=3)
-25)  43781288 (100.0%) *@Group      0       g_chrome_content_browser_client (count=1)
-26)  43781288 (100.0%) *@Group      0       ff_cos_131072_fixed (count=1)
-27)  43784713 (100.0%) *@Group      3425    ** merge constants (count=1)
-28)  43784768 (100.0%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
-29)  43784796 (100.0%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-30)  43784852 (100.0%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
-31)  43784884 (100.0%) *@Group      32      .Lswitch.table.45 (count=1)
-32)  43784888 (100.0%) *@Group      4       FooAlias (count=1)
-33)  43784904 (100.0%) *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
-34)  43785352 (100.0%) *@Group      448     ucnv_extMatchFromU (count=1)
-35)  43785380 (100.0%) *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
-GroupedByName(depth=-1)
-Showing 39 symbols (39 unique) with total pss: 43785380 bytes
-.text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
-
-Index, Running Total, Section@Address, PSS
-------------------------------------------------------------
-0)          8 (0.0%)  *@Group      8        (count=1)
-1)         64 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
-2)         64 (0.0%)  *@Group      0       ff_cos_65536 (count=1)
-3)         68 (0.0%)  *@Group      4       BarAlias (count=1)
-4)        138 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
-5)        138 (0.0%)  *@Group      0       SaveHistogram (count=1)
-6)        170 (0.0%)  *@Group      32      chrome::mojom::FilePatcher (count=1)
-7)    2638139 (6.0%)  *@Group      2637969 ** merge strings (count=2)
-8)    2638139 (6.0%)  *@Group      0       ff_cos_131072_fixed (count=1)
-9)    2638151 (6.0%)  *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
-10)   2638175 (6.0%)  *@Group      24      mojo (count=1)
-11)   2638231 (6.0%)  *@Group      56      ChromeMainDelegate [vtable] (count=1)
-12)   2638239 (6.0%)  *@Group      8       kSystemClassPrefixes (count=1)
-13)   7091083 (16.2%) *@Group      4452844 ** symbol gap 3 (end of section) (count=3)
-14)   7091083 (16.2%) *@Group      0       ff_cos_131072 (count=1)
-15)   7160207 (16.4%) *@Group      69124   foo_bar (count=1)
-16)   7160207 (16.4%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
-17)   7160210 (16.4%) *@Group      3       ** symbol gap 2 (count=1)
-18)   7164250 (16.4%) *@Group      4040    ** symbol gap 1 (count=1)
-19)   7169968 (16.4%) *@Group      5718    ** symbol gap 0 (count=1)
-20)   7169972 (16.4%) *@Group      4       blink::CSSValueKeywordsHash::findValueImpl (count=1)
-21)   7170016 (16.4%) *@Group      44      Name (count=1)
-22)   7170176 (16.4%) *@Group      160     base::android (count=3)
-23)   7170200 (16.4%) *@Group      24      BazAlias (count=1)
-24)  42991202 (98.2%) *@Group      35821002 ** symbol gap 2 (end of section) (count=1)
-25)  42991202 (98.2%) *@Group      0       g_chrome_content_browser_client (count=1)
-26)  42991258 (98.2%) *@Group      56      blink::ContiguousContainerBase (count=3)
-27)  42991352 (98.2%) *@Group      94      blink::PaintChunker (count=1)
-28)  42994777 (98.2%) *@Group      3425    ** merge constants (count=1)
-29)  42994832 (98.2%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
-30)  42994860 (98.2%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-31)  43784788 (100.0%) *@Group      789928  chrome::mojom (count=2)
-32)  43784844 (100.0%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
-33)  43784876 (100.0%) *@Group      32      .Lswitch.table.45 (count=1)
-34)  43784884 (100.0%) *@Group      8       google::protobuf::internal (count=2)
-35)  43784888 (100.0%) *@Group      4       FooAlias (count=1)
-36)  43784904 (100.0%) *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
-37)  43785352 (100.0%) *@Group      448     ucnv_extMatchFromU (count=1)
-38)  43785380 (100.0%) *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
+0)         16 (0.0%)  *@Group      16      _GLOBAL__sub_I_page_allocator.cc (count=1)
+1)         72 (0.0%)  *@Group      56      _GLOBAL__sub_I_bbr_sender.cc (count=1)
+2)        100 (0.0%)  *@Group      28      _GLOBAL__sub_I_pacing_sender.cc (count=1)
+3)        170 (0.0%)  *@Group      70      extFromUUseMapping (count=2)
+4)   39117045 (89.3%) *@Group      39116875 ** symbol gaps (count=2)
+5)   39117493 (89.3%) *@Group      448     ucnv_extMatchFromU (count=1)
+6)   39117521 (89.3%) *@Group      28      _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+7)   39186645 (89.5%) *@Group      69124   foo_bar (count=1)
+8)   39186701 (89.5%) *@Group      56      blink::ContiguousContainerBase (count=3)
+9)   39186725 (89.5%) *@Group      24      BazAlias (count=1)
+10)  39186729 (89.5%) *@Group      4       FooAlias (count=1)
+11)  39186733 (89.5%) *@Group      4       BarAlias (count=1)
+12)  39186827 (89.5%) *@Group      94      blink::PaintChunker (count=1)
+13)  41824796 (95.5%) *@Group      2637969 ** merge strings (count=1)
+14)  41828221 (95.5%) *@Group      3425    ** merge constants (count=1)
+15)  41828229 (95.5%) *@Group      8        (count=1)
+16)  41828273 (95.5%) *@Group      44      Name (count=1)
+17)  41828305 (95.5%) *@Group      32      chrome::mojom::FilePatcher (count=1)
+18)  41828360 (95.5%) *@Group      55      kAnimationFrameTimeHistogramClassPath (count=1)
+19)  41828364 (95.5%) *@Group      4       blink::CSSValueKeywordsHash::findValueImpl (count=1)
+20)  41828420 (95.5%) *@Group      56      ChromeMainDelegate [vtable] (count=1)
+21)  42618348 (97.3%) *@Group      789928  chrome::mojom (count=2)
+22)  42618380 (97.3%) *@Group      32      .Lswitch.table.45 (count=1)
+23)  42618388 (97.3%) *@Group      8       kSystemClassPrefixes (count=1)
+24)  42618444 (97.3%) *@Group      56      ChromeMainDelegateAndroid [vtable] (count=1)
+25)  42618468 (97.3%) *@Group      24      mojo (count=1)
+26)  42618480 (97.3%) *@Group      12      kMethodsAnimationFrameTimeHistogram (count=1)
+27)  43785212 (100.0%) *@Group      1166732 ** symbol gap 0 (end of section) (count=2)
+28)  43785220 (100.0%) *@Group      8       google::protobuf::internal (count=2)
+29)  43785380 (100.0%) *@Group      160     base::android (count=3)
+30)  43785380 (100.0%) *@Group      0       ff_cos_131072 (count=1)
+31)  43785380 (100.0%) *@Group      0       ff_cos_131072_fixed (count=1)
+32)  43785380 (100.0%) *@Group      0       ff_cos_65536 (count=1)
+33)  43785380 (100.0%) *@Group      0       g_chrome_content_browser_client (count=1)
+34)  43785380 (100.0%) *@Group      0       SaveHistogram (count=1)
+35)  43785380 (100.0%) *@Group      0       g_AnimationFrameTimeHistogram_clazz (count=1)
 GroupedByName(depth=1, min_count=2)
-Showing 36 symbols (35 unique) with total pss: 43785380 bytes
+Showing 33 symbols (32 unique) with total pss: 43785380 bytes
 .text=34.2mb     .rodata=5.65mb     .data*=1.87mb     .bss=512kb      total=41.8mb
-Number of object files: 10
+Number of unique paths: 9
 
 Index, Running Total, Section@Address, PSS
 ------------------------------------------------------------
-0)          8 (0.0%)  r@0x284e364  8       base/page_allocator.cc
-1)         64 (0.0%)  t@0x28d910   56      base/page_allocator.cc
-             _GLOBAL__sub_I_bbr_sender.cc
-2)         64 (0.0%)  b@0x0        131072  third_party/fft_float.cc
-             ff_cos_65536
-3)         72 (0.0%)  *@Group      8       {no path}
-             google (count=2)
-4)         76 (0.0%)  t@0x2a0010   4       third_party/fft_float.cc
-             BarAlias
-5)        146 (0.0%)  *@Group      70      base/page_allocator.cc
-             extFromUUseMapping (count=2)
-6)        146 (0.0%)  b@0x2dffe80  200     third_party/icu/ucnv_ext.c
-             SaveHistogram::atomic_histogram_pointer
-7)        300 (0.0%)  *@Group      154     {no path}
-             blink (count=5)
-8)    2638269 (6.0%)  *@Group      2637969 {no path}
-             ** merge strings (count=2)
-9)    2638281 (6.0%)  d@0x2cd8550  12      base/page_allocator.cc
-             kMethodsAnimationFrameTimeHistogram
-10)   2638305 (6.0%)  d@0x2cd8538  24      base/page_allocator.cc
-             mojo::MessageReceiver [vtable]
-11)   2638361 (6.0%)  d@0x2c176f0  56      third_party/icu/ucnv_ext.c
-             ChromeMainDelegate [vtable]
-12)   2638369 (6.0%)  d@0x2cd84f0  8       third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
-             kSystemClassPrefixes
-13)   7091213 (16.2%) *@Group      4452844 {no path}
-             ** symbol gap 3 (end of section) (count=3)
-14)   7091213 (16.2%) b@0x0        262144  third_party/fft_float.cc
-             ff_cos_131072
-15)   7881173 (18.0%) *@Group      789960  {no path}
-             chrome (count=3)
-16)   7950297 (18.2%) t@0x28f1e0   69124   third_party/icu/ucnv_ext.c
-             foo_bar
-17)   7950297 (18.2%) b@0x2dffe84  4       third_party/icu/ucnv_ext.c
-             g_AnimationFrameTimeHistogram_clazz
-18)   7950300 (18.2%) r@0x284e364  3       {no path}
-             ** symbol gap 2
-19)   7954340 (18.2%) t@0x2a1000   4040    {no path}
-             ** symbol gap 1
-20)   7960058 (18.2%) t@0x28f000   5718    {no path}
-             ** symbol gap 0
-21)   7960102 (18.2%) r@0x284e370  44      base/page_allocator.cc
-             Name
-22)   7960126 (18.2%) t@0x2a0000   24      third_party/icu/ucnv_ext.c
-             BazAlias
-23)  43781128 (100.0%) t@0x24ca628  35821002 {no path}
-             ** symbol gap 2 (end of section)
-24)  43781288 (100.0%) *@Group      160     third_party/container.c
-             base (count=3)
-25)  43781288 (100.0%) b@0x2dffda0  28      third_party/icu/ucnv_ext.c
-             g_chrome_content_browser_client
-26)  43781288 (100.0%) b@0x0        131072  third_party/fft_fixed.cc
-             ff_cos_131072_fixed
-27)  43784713 (100.0%) r@0x284d600  3425    {no path}
-             ** merge constants
-28)  43784768 (100.0%) r@0x28f3450  55      third_party/paint.cc
-             kAnimationFrameTimeHistogramClassPath
-29)  43784796 (100.0%) t@0x28f1c8   28      third_party/icu/ucnv_ext.c
-             _GLOBAL__sub_I_SkDeviceProfile.cpp
-30)  43784852 (100.0%) d@0x2cd8500  56      third_party/paint.cc
-             ChromeMainDelegateAndroid [vtable]
-31)  43784884 (100.0%) d@0x2cd84e0  32      third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
-             .Lswitch.table.45
-32)  43784888 (100.0%) t@0x2a0010   4       third_party/fft_float.cc
-             FooAlias
-33)  43784904 (100.0%) t@0x28d900   16      base/page_allocator.cc
+0)         16 (0.0%)  t@0x28d900   16      base/page_allocator.cc
              _GLOBAL__sub_I_page_allocator.cc
-34)  43785352 (100.0%) t@0x28f000   448     third_party/icu/ucnv_ext.c
-             ucnv_extMatchFromU
-35)  43785380 (100.0%) t@0x28d948   28      base/page_allocator.cc
+1)         72 (0.0%)  t@0x28d910   56      base/page_allocator.cc
+             _GLOBAL__sub_I_bbr_sender.cc
+2)        100 (0.0%)  t@0x28d948   28      base/page_allocator.cc
              _GLOBAL__sub_I_pacing_sender.cc
+3)        170 (0.0%)  *@Group      70      base/page_allocator.cc
+             extFromUUseMapping (count=2)
+4)   39117045 (89.3%) *@Group      39116875 {no path}
+             ** symbol gaps (count=2)
+5)   39117493 (89.3%) t@0x28f000   448     third_party/icu/ucnv_ext.c
+             ucnv_extMatchFromU
+6)   39117521 (89.3%) t@0x28f1c8   28      third_party/icu/ucnv_ext.c
+             _GLOBAL__sub_I_SkDeviceProfile.cpp
+7)   39186645 (89.5%) t@0x28f1e0   69124   third_party/icu/ucnv_ext.c
+             foo_bar
+8)   39186799 (89.5%) *@Group      154     {no path}
+             blink (count=5)
+9)   39186823 (89.5%) t@0x2a0000   24      third_party/icu/ucnv_ext.c
+             BazAlias
+10)  39186827 (89.5%) t@0x2a0010   4       third_party/fft_float.cc
+             FooAlias
+11)  39186831 (89.5%) t@0x2a0010   4       third_party/fft_float.cc
+             BarAlias
+12)  41824800 (95.5%) r@Group      2637969 {no path}
+             ** merge strings (count=2)
+13)  41828225 (95.5%) r@0x284d600  3425    {no path}
+             ** merge constants
+14)  41828233 (95.5%) r@0x284e364  8       base/page_allocator.cc
+15)  41828277 (95.5%) r@0x284e370  44      base/page_allocator.cc
+             Name
+16)  42618237 (97.3%) *@Group      789960  {no path}
+             chrome (count=3)
+17)  42618292 (97.3%) r@0x28f3450  55      third_party/paint.cc
+             kAnimationFrameTimeHistogramClassPath
+18)  42618348 (97.3%) d@0x2c176f0  56      third_party/icu/ucnv_ext.c
+             ChromeMainDelegate [vtable]
+19)  42618380 (97.3%) d@0x2cd84e0  32      third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o
+             .Lswitch.table.45
+20)  42618388 (97.3%) d@0x2cd84f0  8       third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
+             kSystemClassPrefixes
+21)  42618444 (97.3%) d@0x2cd8500  56      third_party/paint.cc
+             ChromeMainDelegateAndroid [vtable]
+22)  42618468 (97.3%) d@0x2cd8538  24      base/page_allocator.cc
+             mojo::MessageReceiver [vtable]
+23)  42618480 (97.3%) d@0x2cd8550  12      base/page_allocator.cc
+             kMethodsAnimationFrameTimeHistogram
+24)  43785212 (100.0%) *@Group      1166732 {no path}
+             ** symbol gap 0 (end of section) (count=2)
+25)  43785220 (100.0%) *@Group      8       {no path}
+             google (count=2)
+26)  43785380 (100.0%) *@Group      160     third_party/container.c
+             base (count=3)
+27)  43785380 (100.0%) b@0x0        262144  third_party/fft_float.cc
+             ff_cos_131072
+28)  43785380 (100.0%) b@0x0        131072  third_party/fft_fixed.cc
+             ff_cos_131072_fixed
+29)  43785380 (100.0%) b@0x0        131072  third_party/fft_float.cc
+             ff_cos_65536
+30)  43785380 (100.0%) b@0x2dffda0  28      third_party/icu/ucnv_ext.c
+             g_chrome_content_browser_client
+31)  43785380 (100.0%) b@0x2dffe80  200     third_party/icu/ucnv_ext.c
+             SaveHistogram::atomic_histogram_pointer
+32)  43785380 (100.0%) b@0x2dffe84  4       third_party/icu/ucnv_ext.c
+             g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
index c1e03c9..df48a626 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
@@ -8,7 +8,7 @@
 from telemetry import benchmark
 
 DESKTOP_PLATFORMS = ['mac', 'linux', 'win', 'chromeos']
-WEBVIEW_PLATFORMS = ['android-webview', 'android-webview-shell']
+WEBVIEW_PLATFORMS = ['android-webview', 'android-webview-instrumentation']
 
 
 class ChromeProxyBypassOnTimeout(ChromeProxyBenchmark):
@@ -364,4 +364,4 @@
 
   @classmethod
   def Name(cls):
-    return 'chrome_proxy_benchmark.quic.transaction'
\ No newline at end of file
+    return 'chrome_proxy_benchmark.quic.transaction'
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 2143f6e..eb215fb 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -20,6 +20,35 @@
 from selenium import webdriver
 from selenium.webdriver.chrome.options import Options
 
+# These network condition values are used in SetNetworkConnection()
+NETWORKS = {
+    '4G': {
+      'latency': 20,
+      'upload_throughput': 4096 * 1024,
+      'download_throughput': 4096 * 1024,
+      'offline': False,
+    },
+    '3G': {
+      'latency': 425,
+      'upload_throughput': 750 * 1024,
+      'download_throughput': 750 * 1024,
+      'offline': False,
+    },
+    '2G': {
+      'latency': 1650,
+      'upload_throughput': 250 * 1024,
+      'download_throughput': 250 * 1024,
+      'offline': False,
+    },
+    'OFFLINE': {
+      'latency': 0,
+      'upload_throughput': 0 * 1024,
+      'download_throughput': 0 * 1024,
+      # This stays false so that Chrome won't disconnect from ChromeDriver.
+      'offline': False,
+    },
+}
+
 def ParseFlags():
   """Parses the given command line arguments.
 
@@ -131,15 +160,21 @@
     _url: The string URL that Chrome will navigate to for this test.
     _has_logs: Boolean flag set when a page is loaded and cleared when logs are
       fetched.
+    _control_network_connection: Boolean signal that this chromedriver instance
+      was meant to support network connection control, and thus had to enable
+      mobile emulation
+    _network_connection: The connection type to use on start up
   """
 
-  def __init__(self):
+  def __init__(self, control_network_connection=False):
     self._flags = ParseFlags()
     self._driver = None
     self._chrome_args = set()
     self._url = ''
     self._logger = GetLogger(name='TestDriver')
     self._has_logs = False
+    self._control_network_connection = control_network_connection
+    self._network_connection = None
 
   def __enter__(self):
     return self
@@ -182,9 +217,16 @@
     """
     self._OverrideChromeArgs()
     capabilities = {
-      'loggingPrefs': {'performance': 'INFO'}
+      'loggingPrefs': {'performance': 'INFO'},
     }
     chrome_options = Options()
+    if self._control_network_connection:
+      capabilities.update({
+        'networkConnectionEnabled': True,
+        'mobileEmulationEnabled': True,
+      })
+      chrome_options.add_experimental_option('mobileEmulation',
+        {'deviceName': 'Google Nexus 5'})
     for arg in self._chrome_args:
       chrome_options.add_argument(arg)
     self._logger.info('Starting Chrome with these flags: %s',
@@ -203,8 +245,13 @@
       desired_capabilities=capabilities, chrome_options=chrome_options)
     driver.command_executor._commands.update({
       'getAvailableLogTypes': ('GET', '/session/$sessionId/log/types'),
-      'getLog': ('POST', '/session/$sessionId/log')})
+      'getLog': ('POST', '/session/$sessionId/log'),
+      'setNetworkConditions':
+        ('POST', '/session/$sessionId/chromium/network_conditions')})
     self._driver = driver
+    if self._control_network_connection:
+      # Set network connection if it was called before LoadURL()
+      self.SetNetworkConnection(self._network_connection)
 
   def _StopDriver(self):
     """Nicely stops the ChromeDriver.
@@ -270,6 +317,23 @@
       'clearHostResolverCache();}')
     self._logger.info('Cleared browser cache. Returned=%s', str(res))
 
+  def SetNetworkConnection(self, connection_type):
+    """Changes the emulated connection type.
+
+    Args:
+      connection_type: the connection type to use according to the dict near the
+        top of the file OR a dictionary specifying the network conditions
+    """
+    if not self._control_network_connection:
+      raise Exception('SetNetworkConnection can only be used with a TestDriver '
+        'initalized with control_network_connection=True')
+    self._network_connection = connection_type
+    network = (NETWORKS[self._network_connection]
+      if connection_type in NETWORKS else connection_type)
+    if self._driver and self._network_connection:
+      self._driver.execute('setNetworkConditions',
+        {'network_conditions': network})
+
   def LoadURL(self, url, timeout=30):
     """Starts Chromium with any arguments previously given and navigates to the
     given URL.
@@ -291,6 +355,18 @@
     self._logger.debug('Loaded page %s', url)
     self._has_logs = True
 
+  def FindElement(self, by, value):
+    """Finds an element on the page.
+
+    Uses the By selector and value given.
+    Args:
+      by: the selenium.webdriver.common.By selector
+      value: the value
+    Returns:
+      a WebElement object
+    """
+    return self._driver.find_element(by=by, value=value)
+
   def ExecuteJavascript(self, script, timeout=30):
     """Executes the given javascript in the browser's current page in an
     anonymous function.
@@ -514,7 +590,7 @@
       'status': self._status,
       'request_type': self._request_type
     }
-    return json.dumps(self_dict)
+    return json.dumps(self_dict, indent=2)
 
   @property
   def response_headers(self):
diff --git a/tools/chrome_proxy/webdriver/examples.py b/tools/chrome_proxy/webdriver/examples.py
deleted file mode 100644
index fcf7ae2..0000000
--- a/tools/chrome_proxy/webdriver/examples.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import sys
-import time
-
-import common
-from common import TestDriver
-from common import IntegrationTest
-
-
-class Examples(IntegrationTest):
-
-  # Simple example integration test.
-  def testCheckPageWithProxy(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://check.googlezip.net/test.html')
-      print 'Document Title: ', t.ExecuteJavascriptStatement('document.title',
-        timeout=1)
-      responses = t.GetHTTPResponses()
-      for response in responses:
-        print "URL: %s, ViaHeader: %s, XHR: %s" % (response.url,
-          response.ResponseHasViaHeader(), response.WasXHR())
-        self.assertHasChromeProxyViaHeader(response)
-
-  # Simple example integration test.
-  def testCheckPageWithoutProxy(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('https://check.googlezip.net/test.html')
-      print 'Document Title: ', t.ExecuteJavascriptStatement('document.title',
-        timeout=1)
-      responses = t.GetHTTPResponses()
-      for response in responses:
-        print "URL: %s, ViaHeader: %s, XHR: %s" % (response.url,
-          response.ResponseHasViaHeader(), response.WasXHR())
-        self.assertNotHasChromeProxyViaHeader(response)
-
-  # Show how to get a histogram.
-  def testPingbackHistogram(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://check.googlezip.net/test.html')
-      t.LoadURL('http://check.googlezip.net/test.html')
-      print t.GetHistogram('DataReductionProxy.Pingback.Attempted')
-
-  # Show how to use WaitForJavascriptExpression
-  def testHTML5(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://html5test.com/')
-      t.WaitForJavascriptExpression(
-        'document.getElementsByClassName("pointsPanel")', 15)
-
-if __name__ == '__main__':
-  IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py
index 3f0de05..ec0f648 100644
--- a/tools/chrome_proxy/webdriver/video.py
+++ b/tools/chrome_proxy/webdriver/video.py
@@ -7,9 +7,11 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
+from common import ParseFlags
 from decorators import NotAndroid
 from decorators import Slow
 
+from selenium.webdriver.common.by import By
 
 class Video(IntegrationTest):
 
@@ -49,7 +51,6 @@
   # Check the compressed video has the same frame count, width, height, and
   # duration as uncompressed.
   @Slow
-  @NotAndroid
   def testVideoMetrics(self):
     expected = {
       'duration': 3.124,
@@ -59,7 +60,8 @@
     }
     with TestDriver() as t:
       t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://check.googlezip.net/cacheable/video/buck_bunny_tiny.html')
+      t.LoadURL(
+          'http://check.googlezip.net/cacheable/video/buck_bunny_tiny.html')
       # Check request was proxied and we got a compressed video back.
       for response in t.GetHTTPResponses():
         self.assertHasChromeProxyViaHeader(response)
@@ -67,8 +69,11 @@
             and 'video' in response.response_headers['content-type']):
           self.assertEqual('video/webm',
             response.response_headers['content-type'])
-      t.ExecuteJavascriptStatement(
-        'document.querySelectorAll("video")[0].play()')
+      if ParseFlags().android:
+        t.FindElement(By.TAG_NAME, "video").click()
+      else:
+        t.ExecuteJavascriptStatement(
+          'document.querySelectorAll("video")[0].play()')
       # Wait for the video to finish playing, plus some headroom.
       time.sleep(5)
       # Check each metric against its expected value.
@@ -79,8 +84,69 @@
           "metric doesn't match expected! Metric=%s Expected=%f Actual=%f"
           % (metric, expected[metric], actual), places=None, delta=0.001)
 
-  # Check the frames of a compressed video.
+  # Check that the compressed video can be seeked. Use a slow network to ensure
+  # the entire video isn't downloaded before we have a chance to seek.
+  #
+  # This test cannot run on android because of control_network_connection=True.
+  # That option is used to reduce flakes that might happen on fast networks,
+  # where the video is completely downloaded before a seeking request can be
+  # sent. The test can be manually simulated by the following steps: set network
+  # emulation in DevTools on Android (via device inspector), load a video, pause
+  # the video, then seek and verify the seek continues to play the video.
+  @Slow
   @NotAndroid
+  def testVideoSeeking(self):
+    with TestDriver(control_network_connection=True) as t:
+      t.SetNetworkConnection("3G")
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.LoadURL(
+          'http://check.googlezip.net/cacheable/video/'+
+          'buck_bunny_640x360_24fps.html')
+      # Play, pause, seek to 1s before the end, play again.
+      t.ExecuteJavascript(
+        '''
+        window.testDone = false;
+        const v = document.getElementsByTagName("video")[0];
+        let first = true;
+        v.onplaying = function() {
+          if (first) {
+            v.pause();
+            first = false;
+          } else {
+            window.testDone = true;
+          }
+        };
+        v.onpause = function() {
+          if (v.currentTime < v.duration) {
+            v.currentTime = v.duration-1;
+            v.play();
+          }
+        };
+        v.play();
+        ''')
+      t.WaitForJavascriptExpression('window.testDone', 10)
+      # Check request was proxied and we got a compressed video back.
+      # We expect to make multiple requests for the video: ensure they
+      # all have the same ETag.
+      video_etag = None
+      num_partial_requests = 0
+      for response in t.GetHTTPResponses():
+        self.assertHasChromeProxyViaHeader(response)
+        rh = response.response_headers
+        if ('content-type' in rh and 'video' in rh['content-type']):
+          self.assertTrue('etag' in rh),
+          self.assertEqual('video/webm', rh['content-type'])
+          if video_etag == None:
+            video_etag = rh['etag']
+          else:
+            self.assertEqual(video_etag, rh['etag'])
+          if ('range' in response.request_headers and
+              response.request_headers['range'] != 'bytes=0-'):
+            num_partial_requests += 1
+      # Also make sure that we had at least one partial Range request.
+      self.assertGreaterEqual(num_partial_requests, 1)
+
+  # Check the frames of a compressed video.
   @Slow
   def testVideoFrames(self):
     self.instrumentedVideoTest('http://check.googlezip.net/cacheable/video/buck_bunny_640x360_24fps_video.html')
@@ -119,7 +185,10 @@
       if attempts >= max_attempts:
         self.fail('Could not get a compressed video after %d tries' % attempts)
       t.ExecuteJavascriptStatement('test.ready = true')
-      wait_time = int(t.ExecuteJavascriptStatement('test.waitTime'))
+      waitTimeQuery = 'test.waitTime'
+      if ParseFlags().android:
+        waitTimeQuery = 'test.androidWaitTime'
+      wait_time = int(t.ExecuteJavascriptStatement(waitTimeQuery))
       t.WaitForJavascriptExpression('test.metrics.complete', wait_time)
       metrics = t.ExecuteJavascriptStatement('test.metrics')
       if not metrics['complete']:
@@ -128,11 +197,13 @@
         raise Exception('Test failed!')
 
   # Make sure YouTube autoplays.
-  @NotAndroid
   def testYoutube(self):
     with TestDriver() as t:
       t.AddChromeArg('--enable-spdy-proxy-auth')
       t.LoadURL('http://data-saver-test.appspot.com/youtube')
+      if ParseFlags().android:
+        # Video won't auto play on Android, so give it a click.
+        t.FindElement(By.ID, 'player').click()
       t.WaitForJavascriptExpression(
         'window.playerState == YT.PlayerState.PLAYING', 30)
       for response in t.GetHTTPResponses():
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 64c5207..3571d315 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -27,14 +27,14 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '301384'
+CLANG_REVISION = '303369'
 
 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ
 if use_head_revision:
   CLANG_REVISION = 'HEAD'
 
 # This is incremented when pushing a new build of Clang at the same revision.
-CLANG_SUB_REVISION=2
+CLANG_SUB_REVISION=1
 
 PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
 
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index ef80412..e9070ef 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -150,7 +150,6 @@
     'sync_unit_tests',
     'udp_proxy',
     'ui_base_unittests',
-    'ui_struct_traits_unittests',
     'ui_touch_selection_unittests',
     'unit_tests',
     'url_ipc_unittests',
@@ -254,7 +253,6 @@
     'gpu_perftests.exe',
     'gpu_unittests.exe',
     'image_operations_bench.exe',
-    'input_device_unittests.exe',
     'interactive_ui_tests.exe',
     'ipc_perftests.exe',
     'ipc_tests.exe',
@@ -286,19 +284,13 @@
     'mojo_public_system_perftests.exe',
     'mojo_public_system_unittests.exe',
     'mojo_system_unittests.exe',
-    'mus_clipboard_unittests.exe',
     'mus_demo_library.dll',
-    'mus_demo_unittests.exe',
     'mus_gpu_unittests.exe',
-    'mus_ime_unittests.exe',
-    'mus_public_unittests.exe',
-    'mus_ws_unittests.exe',
     'nacl_irt_x86_32.nexe',
     'nacl_irt_x86_64.nexe',
     'nacl_loader_unittests.exe',
     'native_theme_unittests.exe',
     'navigation.exe',
-    'navigation_unittests.exe',
     'net_perftests.exe',
     'net_unittests.exe',
     'next_version_mini_installer.exe',
@@ -343,6 +335,7 @@
     'udp_proxy.exe',
     'ui_base_unittests.exe',
     'ui_library.dll',
+    'ui_service_unittests.exe',
     'ui_struct_traits_unittests.exe',
     'ui_touch_selection_unittests.exe',
     'unit_tests.exe',
diff --git a/tools/gdb/gdb_chrome.py b/tools/gdb/gdb_chrome.py
index 9d72743..f3073e3 100644
--- a/tools/gdb/gdb_chrome.py
+++ b/tools/gdb/gdb_chrome.py
@@ -14,6 +14,12 @@
 Use
   (gdb) p /r any_variable
 to print |any_variable| without using any printers.
+
+To interactively type Python for development of the printers:
+  (gdb) python foo = gdb.parse_and_eval('bar')
+to put the C++ value 'bar' in the current scope into a Python variable 'foo'.
+Then you can interact with that variable:
+  (gdb) python print foo['impl_']
 """
 
 import datetime
@@ -231,6 +237,62 @@
 pp_set.add_printer('base::Time', '^base::Time$', TimePrinter)
 
 
+class ManualConstructorPrinter(object):
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return self.val['space_'].cast(self.val.type.template_argument(0))
+pp_set.add_printer('base::ManualConstructor', '^base::ManualConstructor<.*>$', ManualConstructorPrinter)
+
+
+class FlatMapPrinter(object):
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        # It would be nice to match the output of std::map which is a little
+        # nicer than printing the vector of pairs. But iterating over it in
+        # Python is much more complicated and this output is reasonable.
+        # (Without this printer, a flat_map will output 7 lines of internal
+        # template goop before the vector contents.)
+        return 'base::flat_map with ' + str(self.val['impl_']['body_'])
+pp_set.add_printer('base::flat_map', '^base::flat_map<.*>$', FlatMapPrinter)
+
+
+class ValuePrinter(object):
+    def __init__(self, val):
+        self.val = val
+
+    def get_type(self):
+        return self.val['type_']
+
+    def to_string(self):
+        typestr = str(self.get_type())
+        # Trim prefix to just get the emum short name.
+        typestr = typestr[typestr.rfind(':') + 1: ]
+
+        if typestr == 'NONE':
+            return 'base::Value of type NONE'
+        if typestr == 'BOOLEAN':
+            valuestr = self.val['bool_value_']
+        if typestr == 'INTEGER':
+            valuestr = self.val['int_value_']
+        if typestr == 'DOUBLE':
+            valuestr = self.val['double_value_']
+        if typestr == 'STRING':
+            valuestr = self.val['string_value_']
+        if typestr == 'BINARY':
+            valuestr = self.val['binary_value_']
+        if typestr == 'DICTIONARY':
+            valuestr = self.val['dict_']
+        if typestr == 'LIST':
+            valuestr = self.val['list_']
+
+        return "base::Value of type %s = %s" % (typestr, str(valuestr))
+pp_set.add_printer('base::Value', '^base::(List|Dictionary|)Value$', ValuePrinter)
+
+
 class IpcMessagePrinter(Printer):
     def header(self):
         return self.val['header_'].cast(
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index f65073d..bd1901c 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -270,7 +270,7 @@
     ":gn_lib",
     ":last_commit_position",
     "//base",
-    "//build/config/sanitizers:deps",
+    "//build/config:exe_and_shlib_deps",
     "//build/win:default_exe_manifest",
   ]
 }
diff --git a/tools/gn/visual_studio_writer.cc b/tools/gn/visual_studio_writer.cc
index aa01d821..a498fb9 100644
--- a/tools/gn/visual_studio_writer.cc
+++ b/tools/gn/visual_studio_writer.cc
@@ -435,6 +435,8 @@
     globals->SubElement("RootNamespace")->Text(target->label().name());
     globals->SubElement("IgnoreWarnCompileDuplicatedFilename")->Text("true");
     globals->SubElement("PreferredToolArchitecture")->Text("x64");
+    globals->SubElement("WindowsTargetPlatformVersion")
+        ->Text(kWindowsKitsIncludeVersion);
   }
 
   project.SubElement(
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 5221b60..25abc65 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -30,24 +30,20 @@
   #
   # chrome/ and ios/chrome/ must start at the same id.
   # App only use one file depending on whether it is iOS or other platform.
-  "chrome/app/address_input_strings.grd": {
-    "messages": [400],
-  },
-
   # Chromium strings and Google Chrome strings must start at the same id.
   # We only use one file depending on whether we're building Chromium or
   # Google Chrome.
   "chrome/app/chromium_strings.grd": {
-    "messages": [500],
+    "messages": [400],
   },
   "chrome/app/google_chrome_strings.grd": {
-    "messages": [500],
+    "messages": [400],
   },
 
   # Leave lots of space for generated_resources since it has most of our
   # strings.
   "chrome/app/generated_resources.grd": {
-    "messages": [900],
+    "messages": [800],
   },
 
   "chrome/app/resources/locale_settings.grd": {
@@ -235,6 +231,12 @@
   "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd": {
     "messages": [3050],
   },
+  "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd": {
+    "messages": [3070],
+  },
+  "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd": {
+    "messages": [3070],
+  },
 
   # content/ and ios/web/ must start at the same id.
   # App only use one file depending on whether it is iOS or other platform.
@@ -358,6 +360,10 @@
     "includes": [28600],
 	"messages": [28650],
   },
+
+  "third_party/libaddressinput/chromium/address_input_strings.grd": {
+    "messages": [28700],
+  },
   # END "everything else" section.
   # Everything but chrome/, components/, content/, and ios/
 
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl
index 8fc2ff1..01c1053 100644
--- a/tools/gritsettings/translation_expectations.pyl
+++ b/tools/gritsettings/translation_expectations.pyl
@@ -22,7 +22,6 @@
     "files": [
       "android_webview/ui/aw_strings.grd",
       "ash/ash_strings.grd",
-      "chrome/app/address_input_strings.grd",
       "chrome/app/chromium_strings.grd",
       "chrome/app/generated_resources.grd",
       "chrome/app/google_chrome_strings.grd",
@@ -39,9 +38,12 @@
       "ios/chrome/app/strings/ios_google_chrome_strings.grd",
       "ios/chrome/app/strings/ios_strings.grd",
       "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_strings.grd",
+      "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_chromium_strings.grd",
+      "ios/chrome/search_widget_extension/strings/ios_search_widget_extension_google_chrome_strings.grd",
       "ios/chrome/share_extension/strings/ios_share_extension_strings.grd",
       "ios/chrome/today_extension/strings/ios_today_extension_strings.grd",
       "remoting/resources/remoting_strings.grd",
+      "third_party/libaddressinput/chromium/address_input_strings.grd",
       "ui/accessibility/extensions/strings/accessibility_extensions_strings.grd",
       "ui/chromeos/ui_chromeos_strings.grd",
       "ui/strings/ui_strings.grd",
diff --git a/tools/imagediff/BUILD.gn b/tools/imagediff/BUILD.gn
index 9273106..66f539a0 100644
--- a/tools/imagediff/BUILD.gn
+++ b/tools/imagediff/BUILD.gn
@@ -17,7 +17,7 @@
 
     deps = [
       "//base",
-      "//build/config/sanitizers:deps",
+      "//build/config:exe_and_shlib_deps",
       "//build/win:default_exe_manifest",
       "//third_party/libpng",
       "//third_party/zlib",
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index a8d3c6c..5474ba84 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -590,25 +590,25 @@
         case base::Value::Type::BOOLEAN: {
           bool tmp;
           fuzzer->FuzzBool(&tmp);
-          p->SetWithoutPathExpansion(property, new base::Value(tmp));
+          p->SetBooleanWithoutPathExpansion(property, tmp);
           break;
         }
         case base::Value::Type::INTEGER: {
           int tmp;
           fuzzer->FuzzInt(&tmp);
-          p->SetWithoutPathExpansion(property, new base::Value(tmp));
+          p->SetIntegerWithoutPathExpansion(property, tmp);
           break;
         }
         case base::Value::Type::DOUBLE: {
           double tmp;
           fuzzer->FuzzDouble(&tmp);
-          p->SetWithoutPathExpansion(property, new base::Value(tmp));
+          p->SetDoubleWithoutPathExpansion(property, tmp);
           break;
         }
         case base::Value::Type::STRING: {
           std::string tmp;
           fuzzer->FuzzString(&tmp);
-          p->SetWithoutPathExpansion(property, new base::Value(tmp));
+          p->SetStringWithoutPathExpansion(property, tmp);
           break;
         }
         case base::Value::Type::BINARY: {
@@ -620,15 +620,15 @@
           break;
         }
         case base::Value::Type::DICTIONARY: {
-          base::DictionaryValue* tmp = new base::DictionaryValue();
-          FuzzParam(tmp, fuzzer);
-          p->SetWithoutPathExpansion(property, tmp);
+          auto tmp = base::MakeUnique<base::DictionaryValue>();
+          FuzzParam(tmp.get(), fuzzer);
+          p->SetWithoutPathExpansion(property, std::move(tmp));
           break;
         }
         case base::Value::Type::LIST: {
-          base::ListValue* tmp = new base::ListValue();
-          FuzzParam(tmp, fuzzer);
-          p->SetWithoutPathExpansion(property, tmp);
+          auto tmp = base::MakeUnique<base::ListValue>();
+          FuzzParam(tmp.get(), fuzzer);
+          p->SetWithoutPathExpansion(property, std::move(tmp));
           break;
         }
         case base::Value::Type::NONE:
diff --git a/tools/json_schema_compiler/test/choices_unittest.cc b/tools/json_schema_compiler/test/choices_unittest.cc
index 35ec229..708c900 100644
--- a/tools/json_schema_compiler/test/choices_unittest.cc
+++ b/tools/json_schema_compiler/test/choices_unittest.cc
@@ -8,7 +8,9 @@
 
 #include <utility>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_piece.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/json_schema_compiler/test/test_util.h"
 
@@ -22,21 +24,22 @@
 
 TEST(JsonSchemaCompilerChoicesTest, TakesIntegersParamsCreate) {
   {
-    std::unique_ptr<TakesIntegers::Params> params(
-        TakesIntegers::Params::Create(*List(new base::Value(true))));
+    std::unique_ptr<TakesIntegers::Params> params(TakesIntegers::Params::Create(
+        *List(base::MakeUnique<base::Value>(true))));
     EXPECT_FALSE(params);
   }
   {
     std::unique_ptr<TakesIntegers::Params> params(
-        TakesIntegers::Params::Create(*List(new base::Value(6))));
+        TakesIntegers::Params::Create(*List(base::MakeUnique<base::Value>(6))));
     ASSERT_TRUE(params);
     EXPECT_FALSE(params->nums.as_integers);
     EXPECT_EQ(6, *params->nums.as_integer);
   }
   {
-    std::unique_ptr<TakesIntegers::Params> params(TakesIntegers::Params::Create(
-        *List(List(new base::Value(2), new base::Value(6), new base::Value(8))
-                  .release())));
+    std::unique_ptr<TakesIntegers::Params> params(
+        TakesIntegers::Params::Create(*List(List(
+            base::MakeUnique<base::Value>(2), base::MakeUnique<base::Value>(6),
+            base::MakeUnique<base::Value>(8)))));
     ASSERT_TRUE(params);
     ASSERT_TRUE(params->nums.as_integers);
     EXPECT_EQ(Vector(2, 6, 8), *params->nums.as_integers);
@@ -46,8 +49,8 @@
 TEST(JsonSchemaCompilerChoicesTest, ObjectWithChoicesParamsCreate) {
   {
     std::unique_ptr<ObjectWithChoices::Params> params(
-        ObjectWithChoices::Params::Create(
-            *List(Dictionary("strings", new base::Value("asdf")).release())));
+        ObjectWithChoices::Params::Create(*List(
+            Dictionary("strings", base::MakeUnique<base::Value>("asdf")))));
     ASSERT_TRUE(params);
     EXPECT_FALSE(params->string_info.strings.as_strings);
     EXPECT_EQ("asdf", *params->string_info.strings.as_string);
@@ -56,9 +59,8 @@
   {
     std::unique_ptr<ObjectWithChoices::Params> params(
         ObjectWithChoices::Params::Create(
-            *List(Dictionary("strings", new base::Value("asdf"), "integers",
-                             new base::Value(6))
-                      .release())));
+            *List(Dictionary("strings", base::MakeUnique<base::Value>("asdf"),
+                             "integers", base::MakeUnique<base::Value>(6)))));
     ASSERT_TRUE(params);
     EXPECT_FALSE(params->string_info.strings.as_strings);
     EXPECT_EQ("asdf", *params->string_info.strings.as_string);
@@ -75,7 +77,7 @@
   {
     std::unique_ptr<base::DictionaryValue> object_param(
         new base::DictionaryValue());
-    object_param->SetWithoutPathExpansion("strings", new base::Value(5));
+    object_param->SetIntegerWithoutPathExpansion("strings", 5);
     std::unique_ptr<base::ListValue> params_value(new base::ListValue());
     params_value->Append(std::move(object_param));
     std::unique_ptr<ObjectWithChoices::Params> params(
@@ -85,8 +87,8 @@
   {
     std::unique_ptr<base::DictionaryValue> object_param(
         new base::DictionaryValue());
-    object_param->SetWithoutPathExpansion("strings", new base::Value("asdf"));
-    object_param->SetWithoutPathExpansion("integers", new base::Value("asdf"));
+    object_param->SetStringWithoutPathExpansion("strings", "asdf");
+    object_param->SetStringWithoutPathExpansion("integers", "asdf");
     std::unique_ptr<base::ListValue> params_value(new base::ListValue());
     params_value->Append(std::move(object_param));
     std::unique_ptr<ObjectWithChoices::Params> params(
@@ -96,7 +98,7 @@
   {
     std::unique_ptr<base::DictionaryValue> object_param(
         new base::DictionaryValue());
-    object_param->SetWithoutPathExpansion("integers", new base::Value(6));
+    object_param->SetIntegerWithoutPathExpansion("integers", 6);
     std::unique_ptr<base::ListValue> params_value(new base::ListValue());
     params_value->Append(std::move(object_param));
     std::unique_ptr<ObjectWithChoices::Params> params(
diff --git a/tools/json_schema_compiler/test/enums_unittest.cc b/tools/json_schema_compiler/test/enums_unittest.cc
index 5318981..715b4ae 100644
--- a/tools/json_schema_compiler/test/enums_unittest.cc
+++ b/tools/json_schema_compiler/test/enums_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "tools/json_schema_compiler/test/enums.h"
 
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/json_schema_compiler/test/test_util.h"
 
@@ -72,7 +74,8 @@
 TEST(JsonSchemaCompilerEnumsTest, EnumsArrayAsType) {
   {
     base::ListValue params_value;
-    params_value.Append(List(new base::Value("one"), new base::Value("two")));
+    params_value.Append(List(base::MakeUnique<base::Value>("one"),
+                             base::MakeUnique<base::Value>("two")));
     std::unique_ptr<TakesEnumArrayAsType::Params> params(
         TakesEnumArrayAsType::Params::Create(params_value));
     ASSERT_TRUE(params);
@@ -82,7 +85,7 @@
   }
   {
     base::ListValue params_value;
-    params_value.Append(List(new base::Value("invalid")));
+    params_value.Append(List(base::MakeUnique<base::Value>("invalid")));
     std::unique_ptr<TakesEnumArrayAsType::Params> params(
         TakesEnumArrayAsType::Params::Create(params_value));
     EXPECT_FALSE(params);
@@ -162,7 +165,8 @@
 TEST(JsonSchemaCompilerEnumsTest, TakesEnumArrayParamsCreate) {
   {
     base::ListValue params_value;
-    params_value.Append(List(new base::Value("one"), new base::Value("two")));
+    params_value.Append(List(base::MakeUnique<base::Value>("one"),
+                             base::MakeUnique<base::Value>("two")));
     std::unique_ptr<TakesEnumArray::Params> params(
         TakesEnumArray::Params::Create(params_value));
     ASSERT_TRUE(params);
@@ -172,7 +176,7 @@
   }
   {
     base::ListValue params_value;
-    params_value.Append(List(new base::Value("invalid")));
+    params_value.Append(List(base::MakeUnique<base::Value>("invalid")));
     std::unique_ptr<TakesEnumArray::Params> params(
         TakesEnumArray::Params::Create(params_value));
     EXPECT_FALSE(params);
diff --git a/tools/json_schema_compiler/test/error_generation_unittest.cc b/tools/json_schema_compiler/test/error_generation_unittest.cc
index 9c22682..06a3a9c 100644
--- a/tools/json_schema_compiler/test/error_generation_unittest.cc
+++ b/tools/json_schema_compiler/test/error_generation_unittest.cc
@@ -36,7 +36,7 @@
 TEST(JsonSchemaCompilerErrorTest, RequiredPropertyPopulate) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value("bling"));
+        Dictionary("string", base::MakeUnique<base::Value>("bling"));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<TestType>(*value)));
   }
   {
@@ -64,7 +64,7 @@
 TEST(JsonSchemaCompilerErrorTest, TypeIsRequired) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("integers", new Value(5));
+        Dictionary("integers", base::MakeUnique<Value>(5));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ChoiceType>(*value)));
   }
   {
@@ -78,13 +78,14 @@
 
 TEST(JsonSchemaCompilerErrorTest, TooManyParameters) {
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value(5));
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>(5));
     base::string16 error;
     EXPECT_TRUE(TestFunction::Params::Create(*params_value, &error));
   }
   {
     std::unique_ptr<base::ListValue> params_value =
-        List(new Value(5), new Value(5));
+        List(base::MakeUnique<Value>(5), base::MakeUnique<Value>(5));
     base::string16 error;
     EXPECT_FALSE(TestFunction::Params::Create(*params_value, &error));
     EXPECT_TRUE(EqualsUtf16("expected 1 arguments, got 2", error));
@@ -95,12 +96,14 @@
 
 TEST(JsonSchemaCompilerErrorTest, ParamIsRequired) {
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value(5));
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>(5));
     base::string16 error;
     EXPECT_TRUE(TestFunction::Params::Create(*params_value, &error));
   }
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value());
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>());
     base::string16 error;
     EXPECT_FALSE(TestFunction::Params::Create(*params_value, &error));
     EXPECT_TRUE(EqualsUtf16("'num' is required", error));
@@ -112,12 +115,12 @@
 TEST(JsonSchemaCompilerErrorTest, WrongPropertyValueType) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value("yes"));
+        Dictionary("string", base::MakeUnique<base::Value>("yes"));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<TestType>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new Value(1.1));
+        Dictionary("string", base::MakeUnique<Value>(1.1));
     EXPECT_TRUE(EqualsUtf16("'string': expected string, got double",
         GetPopulateError<TestType>(*value)));
   }
@@ -127,11 +130,12 @@
   {
     base::string16 error;
     std::unique_ptr<base::ListValue> params_value =
-        List(new base::Value("Yeah!"));
+        List(base::MakeUnique<base::Value>("Yeah!"));
     EXPECT_TRUE(TestString::Params::Create(*params_value, &error));
   }
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value(5));
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>(5));
     base::string16 error;
     EXPECT_FALSE(TestTypeInObject::Params::Create(*params_value, &error));
     EXPECT_TRUE(EqualsUtf16("'paramObject': expected dictionary, got integer",
@@ -146,7 +150,7 @@
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("otherType", new Value(1.1));
+        Dictionary("otherType", base::MakeUnique<Value>(1.1));
     ObjectType out;
     base::string16 error;
     EXPECT_TRUE(ObjectType::Populate(*value, &out, &error));
@@ -158,13 +162,14 @@
 
 TEST(JsonSchemaCompilerErrorTest, UnableToPopulateArray) {
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value(5));
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>(5));
     EXPECT_TRUE(EqualsUtf16("",
         GetPopulateError<ChoiceType::Integers>(*params_value)));
   }
   {
     std::unique_ptr<base::ListValue> params_value =
-        List(new Value(5), new Value(false));
+        List(base::MakeUnique<Value>(5), base::MakeUnique<Value>(false));
     EXPECT_TRUE(EqualsUtf16(
         "expected integer, got boolean; unable to populate array 'integers'",
         GetPopulateError<ChoiceType::Integers>(*params_value)));
@@ -173,13 +178,13 @@
 
 TEST(JsonSchemaCompilerErrorTest, BinaryTypeExpected) {
   {
-    std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("data", new base::Value(base::Value::Type::BINARY));
+    std::unique_ptr<base::DictionaryValue> value = Dictionary(
+        "data", base::MakeUnique<base::Value>(base::Value::Type::BINARY));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<BinaryData>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("data", new Value(1.1));
+        Dictionary("data", base::MakeUnique<Value>(1.1));
     EXPECT_TRUE(EqualsUtf16("'data': expected binary, got double",
         GetPopulateError<BinaryData>(*value)));
   }
@@ -188,12 +193,12 @@
 TEST(JsonSchemaCompilerErrorTest, ListExpected) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("TheArray", new base::ListValue());
+        Dictionary("TheArray", base::MakeUnique<base::ListValue>());
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ArrayObject>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("TheArray", new Value(5));
+        Dictionary("TheArray", base::MakeUnique<Value>(5));
     EXPECT_TRUE(EqualsUtf16("'TheArray': expected list, got integer",
         GetPopulateError<ArrayObject>(*value)));
   }
@@ -204,12 +209,12 @@
 TEST(JsonSchemaCompilerErrorTest, BadEnumValue) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("enumeration", new base::Value("one"));
+        Dictionary("enumeration", base::MakeUnique<base::Value>("one"));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<HasEnumeration>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("enumeration", new base::Value("bad sauce"));
+        Dictionary("enumeration", base::MakeUnique<base::Value>("bad sauce"));
     EXPECT_TRUE(EqualsUtf16("'Enumeration': expected \"one\" or \"two\" "
               "or \"three\", got \"bad sauce\"",
         GetPopulateError<HasEnumeration>(*value)));
@@ -221,12 +226,12 @@
 TEST(JsonSchemaCompilerErrorTest, WarnOnOptionalFailure) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value("bling"));
+        Dictionary("string", base::MakeUnique<base::Value>("bling"));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<OptionalTestType>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value(1));
+        Dictionary("string", base::MakeUnique<base::Value>(1));
 
     OptionalTestType out;
     base::string16 error;
@@ -239,14 +244,14 @@
 
 TEST(JsonSchemaCompilerErrorTest, OptionalBinaryTypeFailure) {
   {
-    std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("data", new base::Value(base::Value::Type::BINARY));
+    std::unique_ptr<base::DictionaryValue> value = Dictionary(
+        "data", base::MakeUnique<base::Value>(base::Value::Type::BINARY));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<OptionalBinaryData>(*value)));
   }
   {
     // There's a bug with silent failures if the key doesn't exist.
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("data", new base::Value(1));
+        Dictionary("data", base::MakeUnique<base::Value>(1));
 
     OptionalBinaryData out;
     base::string16 error;
@@ -260,12 +265,12 @@
 TEST(JsonSchemaCompilerErrorTest, OptionalArrayTypeFailure) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("TheArray", new base::ListValue());
+        Dictionary("TheArray", base::MakeUnique<base::ListValue>());
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ArrayObject>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("TheArray", new Value(5));
+        Dictionary("TheArray", base::MakeUnique<Value>(5));
     ArrayObject out;
     base::string16 error;
     EXPECT_TRUE(ArrayObject::Populate(*value, &out, &error));
@@ -277,13 +282,14 @@
 
 TEST(JsonSchemaCompilerErrorTest, OptionalUnableToPopulateArray) {
   {
-    std::unique_ptr<base::ListValue> params_value = List(new Value(5));
+    std::unique_ptr<base::ListValue> params_value =
+        List(base::MakeUnique<Value>(5));
     EXPECT_TRUE(EqualsUtf16("",
         GetPopulateError<OptionalChoiceType::Integers>(*params_value)));
   }
   {
     std::unique_ptr<base::ListValue> params_value =
-        List(new Value(5), new Value(false));
+        List(base::MakeUnique<Value>(5), base::MakeUnique<Value>(false));
     OptionalChoiceType::Integers out;
     base::string16 error;
     EXPECT_TRUE(OptionalChoiceType::Integers::Populate(*params_value, &out,
@@ -298,7 +304,7 @@
 TEST(JsonSchemaCompilerErrorTest, MultiplePopulationErrors) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("TheArray", new Value(5));
+        Dictionary("TheArray", base::MakeUnique<Value>(5));
     ArrayObject out;
     base::string16 error;
     EXPECT_TRUE(ArrayObject::Populate(*value, &out, &error));
@@ -317,13 +323,13 @@
 TEST(JsonSchemaCompilerErrorTest, TooManyKeys) {
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value("yes"));
+        Dictionary("string", base::MakeUnique<base::Value>("yes"));
     EXPECT_TRUE(EqualsUtf16("", GetPopulateError<TestType>(*value)));
   }
   {
     std::unique_ptr<base::DictionaryValue> value =
-        Dictionary("string", new base::Value("yes"), "ohno",
-                   new base::Value("many values"));
+        Dictionary("string", base::MakeUnique<base::Value>("yes"), "ohno",
+                   base::MakeUnique<base::Value>("many values"));
     EXPECT_TRUE(EqualsUtf16("found unexpected key 'ohno'",
         GetPopulateError<TestType>(*value)));
   }
diff --git a/tools/json_schema_compiler/test/simple_api_unittest.cc b/tools/json_schema_compiler/test/simple_api_unittest.cc
index 54c773f2..ef6f9e2 100644
--- a/tools/json_schema_compiler/test/simple_api_unittest.cc
+++ b/tools/json_schema_compiler/test/simple_api_unittest.cc
@@ -5,6 +5,7 @@
 #include "tools/json_schema_compiler/test/simple_api.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using namespace test::api::simple_api;
@@ -13,10 +14,10 @@
 
 static std::unique_ptr<base::DictionaryValue> CreateTestTypeDictionary() {
   std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
-  value->SetWithoutPathExpansion("number", new base::Value(1.1));
-  value->SetWithoutPathExpansion("integer", new base::Value(4));
-  value->SetWithoutPathExpansion("string", new base::Value("bling"));
-  value->SetWithoutPathExpansion("boolean", new base::Value(true));
+  value->SetDoubleWithoutPathExpansion("number", 1.1);
+  value->SetIntegerWithoutPathExpansion("integer", 4);
+  value->SetStringWithoutPathExpansion("string", "bling");
+  value->SetBooleanWithoutPathExpansion("boolean", true);
   return value;
 }
 
diff --git a/tools/json_schema_compiler/test/test_util.cc b/tools/json_schema_compiler/test/test_util.cc
index 60744ba..d6665fcb 100644
--- a/tools/json_schema_compiler/test/test_util.cc
+++ b/tools/json_schema_compiler/test/test_util.cc
@@ -5,6 +5,7 @@
 #include "tools/json_schema_compiler/test/test_util.h"
 
 #include <string>
+#include <utility>
 
 #include "base/json/json_reader.h"
 #include "base/logging.h"
@@ -23,46 +24,56 @@
   return result;
 }
 
-std::unique_ptr<base::ListValue> List(base::Value* a) {
-  std::unique_ptr<base::ListValue> list(new base::ListValue());
-  list->Append(base::WrapUnique(a));
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a) {
+  auto list = base::MakeUnique<base::ListValue>();
+  list->Append(std::move(a));
   return list;
 }
-std::unique_ptr<base::ListValue> List(base::Value* a, base::Value* b) {
-  std::unique_ptr<base::ListValue> list = List(a);
-  list->Append(base::WrapUnique(b));
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a,
+                                      std::unique_ptr<base::Value> b) {
+  auto list = base::MakeUnique<base::ListValue>();
+  list->Append(std::move(a));
+  list->Append(std::move(b));
   return list;
 }
-std::unique_ptr<base::ListValue> List(base::Value* a,
-                                      base::Value* b,
-                                      base::Value* c) {
-  std::unique_ptr<base::ListValue> list = List(a, b);
-  list->Append(base::WrapUnique(c));
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a,
+                                      std::unique_ptr<base::Value> b,
+                                      std::unique_ptr<base::Value> c) {
+  auto list = base::MakeUnique<base::ListValue>();
+  list->Append(std::move(a));
+  list->Append(std::move(b));
+  list->Append(std::move(c));
   return list;
 }
 
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetWithoutPathExpansion(ak, av);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av) {
+  auto dict = base::MakeUnique<base::DictionaryValue>();
+  dict->SetWithoutPathExpansion(ak, std::move(av));
   return dict;
 }
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av,
-                                                  const std::string& bk,
-                                                  base::Value* bv) {
-  std::unique_ptr<base::DictionaryValue> dict = Dictionary(ak, av);
-  dict->SetWithoutPathExpansion(bk, bv);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av,
+    const std::string& bk,
+    std::unique_ptr<base::Value> bv) {
+  auto dict = base::MakeUnique<base::DictionaryValue>();
+  dict->SetWithoutPathExpansion(ak, std::move(av));
+  dict->SetWithoutPathExpansion(bk, std::move(bv));
   return dict;
 }
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av,
-                                                  const std::string& bk,
-                                                  base::Value* bv,
-                                                  const std::string& ck,
-                                                  base::Value* cv) {
-  std::unique_ptr<base::DictionaryValue> dict = Dictionary(ak, av, bk, bv);
-  dict->SetWithoutPathExpansion(ck, cv);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av,
+    const std::string& bk,
+    std::unique_ptr<base::Value> bv,
+    const std::string& ck,
+    std::unique_ptr<base::Value> cv) {
+  auto dict = base::MakeUnique<base::DictionaryValue>();
+  dict->SetWithoutPathExpansion(ak, std::move(av));
+  dict->SetWithoutPathExpansion(bk, std::move(bv));
+  dict->SetWithoutPathExpansion(ck, std::move(cv));
   return dict;
 }
 
diff --git a/tools/json_schema_compiler/test/test_util.h b/tools/json_schema_compiler/test/test_util.h
index 87145fd..53eb38d 100644
--- a/tools/json_schema_compiler/test/test_util.h
+++ b/tools/json_schema_compiler/test/test_util.h
@@ -34,26 +34,28 @@
   return arr;
 }
 
-// TODO(dcheng): These various helpers should all take std::unique_ptr
-// arguments. See https://crbug.com/581865.
-std::unique_ptr<base::ListValue> List(base::Value* a);
-std::unique_ptr<base::ListValue> List(base::Value* a, base::Value* b);
-std::unique_ptr<base::ListValue> List(base::Value* a,
-                                      base::Value* b,
-                                      base::Value* c);
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a);
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a,
+                                      std::unique_ptr<base::Value> b);
+std::unique_ptr<base::ListValue> List(std::unique_ptr<base::Value> a,
+                                      std::unique_ptr<base::Value> b,
+                                      std::unique_ptr<base::Value> c);
 
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av);
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av,
-                                                  const std::string& bk,
-                                                  base::Value* bv);
-std::unique_ptr<base::DictionaryValue> Dictionary(const std::string& ak,
-                                                  base::Value* av,
-                                                  const std::string& bk,
-                                                  base::Value* bv,
-                                                  const std::string& ck,
-                                                  base::Value* cv);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av,
+    const std::string& bk,
+    std::unique_ptr<base::Value> bv);
+std::unique_ptr<base::DictionaryValue> Dictionary(
+    const std::string& ak,
+    std::unique_ptr<base::Value> av,
+    const std::string& bk,
+    std::unique_ptr<base::Value> bv,
+    const std::string& ck,
+    std::unique_ptr<base::Value> cv);
 
 }  // namespace test_util
 }  // namespace json_schema_compiler
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 11a30f3..46bf07b7 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -952,12 +952,6 @@
     labels = []
     err = ''
 
-    def StripTestSuffixes(target):
-      for suffix in ('_apk_run', '_apk', '_run'):
-        if target.endswith(suffix):
-          return target[:-len(suffix)], suffix
-      return None, None
-
     for target in targets:
       if target == 'all':
         labels.append(target)
@@ -965,14 +959,10 @@
         labels.append(target)
       else:
         if target in isolate_map:
-          stripped_target, suffix = target, ''
-        else:
-          stripped_target, suffix = StripTestSuffixes(target)
-        if stripped_target in isolate_map:
-          if isolate_map[stripped_target]['type'] == 'unknown':
+          if isolate_map[target]['type'] == 'unknown':
             err += ('test target "%s" type is unknown\n' % target)
           else:
-            labels.append(isolate_map[stripped_target]['label'] + suffix)
+            labels.append(isolate_map[target]['label'])
         else:
           err += ('target "%s" not found in '
                   '//testing/buildbot/gn_isolate_map.pyl\n' % target)
@@ -1091,7 +1081,8 @@
           '--target', target,
           '--target-devices-file', '${SWARMING_BOT_FILE}',
           '--logdog-bin-cmd', '../../bin/logdog_butler',
-          '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats']
+          '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats',
+          '--store-tombstones']
     elif use_xvfb and test_type == 'windowed_test_launcher':
       extra_files = [
           '../../testing/test_env.py',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a17e5f4..11d6f1d4 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -240,7 +240,6 @@
       'Android Release (Nexus 6)': 'android_release_trybot',
       'Android Release (Nexus 6P)': 'android_release_trybot_arm64',
       'Android Release (Nexus 9)': 'android_release_trybot_arm64',
-      'Android Release (Pixel C)': 'android_release_trybot_arm64',
       'Android Release (NVIDIA Shield TV)': 'android_release_trybot_arm64',
       'GPU Linux Builder (dbg)': 'gpu_fyi_tests_debug_trybot',
       'GPU Linux Builder': 'gpu_fyi_tests_release_trybot',
@@ -344,7 +343,9 @@
       'Android Builder FYI': 'official_goma_minimal_symbols_android',
       'Win Builder FYI': 'official_goma',
       'Win Clang Builder': 'official_goma_minimal_symbols_clang',
-      'Battor Agent Linux': 'debug_bot',
+      'Battor Agent Linux': 'official_goma_minimal_symbols_clang',
+      'Battor Agent Mac': 'official_goma_minimal_symbols_clang',
+      'Battor Agent Win': 'official_goma_minimal_symbols_clang',
     },
 
     'chromium.swarm': {
@@ -735,27 +736,27 @@
     ],
 
     'android_cronet_release_bot_minimal_symbols_arm64': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'arm64',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'arm64',
     ],
 
     'android_cronet_release_bot_minimal_symbols_armv6': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'armv6',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'armv6',
     ],
 
     'android_cronet_release_bot_minimal_symbols_arm_no_neon': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'arm_no_neon',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'arm_no_neon',
     ],
 
     'android_cronet_release_bot_minimal_symbols_arm_no_neon_clang_asan': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'arm_no_neon', 'clang', 'asan',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'arm_no_neon', 'clang', 'asan',
     ],
 
     'android_cronet_release_bot_minimal_symbols_mipsel': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'mipsel',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'mipsel',
     ],
 
     'android_cronet_release_bot_minimal_symbols_x86': [
-      'android', 'cronet', 'release_bot', 'minimal_symbols', 'x86',
+      'android', 'cronet', 'official_optimize', 'release_bot', 'minimal_symbols', 'x86',
     ],
 
     'android_cronet_release_trybot_arm_no_neon': [
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 741af6bf..34449e5 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1283,6 +1283,11 @@
   </description>
 </action>
 
+<action name="Android.DownloadManager.Item.OpenSucceeded">
+  <owner>shaktisahu@chromium.org</owner>
+  <description>User opened a download from download home.</description>
+</action>
+
 <action name="Android.DownloadManager.OpenDrawer">
   <owner>dfalcantara@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -15099,7 +15104,7 @@
   </description>
 </action>
 
-<action name="Signin_SigninNoDefault_FromBookmarkManager">
+<action name="Signin_SigninNotDefault_FromBookmarkManager">
   <owner>jlebel@chromium.org</owner>
   <description>
     Recorded on sign in start from access point
@@ -15108,7 +15113,7 @@
   </description>
 </action>
 
-<action name="Signin_SigninNoDefault_FromRecentTabs">
+<action name="Signin_SigninNotDefault_FromRecentTabs">
   <owner>jlebel@chromium.org</owner>
   <description>
     Recorded on sign in start from access point
@@ -15117,7 +15122,7 @@
   </description>
 </action>
 
-<action name="Signin_SigninNoDefault_FromSettings">
+<action name="Signin_SigninNotDefault_FromSettings">
   <owner>jlebel@chromium.org</owner>
   <description>
     Recorded on sign in start from access point
@@ -16084,6 +16089,15 @@
   </description>
 </action>
 
+<action name="Suggestions.FirstTimeSurfaceVisible">
+  <owner>finkm@chromium.org</owner>
+  <owner>dgn@chromium.org</owner>
+  <description>
+    Recorded right before Suggestions.SurfaceVisible when this is the first time
+    a suggestions surface is made visible to the user on that device.
+  </description>
+</action>
+
 <action name="Suggestions.ScrolledAfterOpen">
   <owner>dgn@chromium.org</owner>
   <owner>finkm@chromium.org</owner>
@@ -16105,6 +16119,25 @@
   <description>User removed a suggested site.</description>
 </action>
 
+<action name="Suggestions.SurfaceFullyVisible">
+  <owner>finkm@chromium.org</owner>
+  <owner>dgn@chromium.org</owner>
+  <description>
+    ChromeHome: The Suggestion surface is loaded or brought in the foreground in
+    its fully visible state. In regular Chrome, MobileNTPShown is the
+    equivalent.
+  </description>
+</action>
+
+<action name="Suggestions.SurfaceHalfVisible">
+  <owner>finkm@chromium.org</owner>
+  <owner>dgn@chromium.org</owner>
+  <description>
+    ChromeHome: The Suggestion surface is loaded or brought in the foreground in
+    its half visible state. In regular Chrome, MobileNTPShown is the equivalent.
+  </description>
+</action>
+
 <action name="Suggestions.SurfaceHidden">
   <owner>finkm@chromium.org</owner>
   <owner>dgn@chromium.org</owner>
diff --git a/tools/metrics/actions/print_style.py b/tools/metrics/actions/print_style.py
index 39deb23..817b148 100644
--- a/tools/metrics/actions/print_style.py
+++ b/tools/metrics/actions/print_style.py
@@ -27,6 +27,13 @@
     'with-suffix': ['name'],
 }
 
+# Attribute names that must be explicitly specified on nodes that support them.
+REQUIRED_ATTRIBUTES = [
+    'label',
+    'name',
+    'separator',
+]
+
 # Tag names for top-level nodes whose children we don't want to indent.
 TAGS_THAT_DONT_INDENT = [
     'actions',
@@ -59,6 +66,7 @@
 def GetPrintStyle():
   """Returns an XmlStyle object for pretty printing actions."""
   return pretty_print_xml.XmlStyle(ATTRIBUTE_ORDER,
+                                   REQUIRED_ATTRIBUTES,
                                    TAGS_THAT_HAVE_EXTRA_NEWLINE,
                                    TAGS_THAT_DONT_INDENT,
                                    TAGS_THAT_ALLOW_SINGLE_LINE,
diff --git a/tools/metrics/common/pretty_print_xml.py b/tools/metrics/common/pretty_print_xml.py
index ea657789..0ad3f4f7 100644
--- a/tools/metrics/common/pretty_print_xml.py
+++ b/tools/metrics/common/pretty_print_xml.py
@@ -66,10 +66,11 @@
 class XmlStyle(object):
   """A class that stores all style specification for an output xml file."""
 
-  def __init__(self, attribute_order, tags_that_have_extra_newline,
-               tags_that_dont_indent, tags_that_allow_single_line,
-               tags_alphabetization_rules):
+  def __init__(self, attribute_order, required_attributes,
+               tags_that_have_extra_newline, tags_that_dont_indent,
+               tags_that_allow_single_line, tags_alphabetization_rules):
     self.attribute_order = attribute_order
+    self.required_attributes = required_attributes
     self.tags_that_have_extra_newline = tags_that_have_extra_newline
     self.tags_that_dont_indent = tags_that_dont_indent
     self.tags_that_allow_single_line = tags_that_allow_single_line
@@ -199,8 +200,27 @@
       if not node.childNodes:
         closing_chars = 2
 
-      # Pretty-print the attributes.
       attributes = node.attributes.keys()
+      required_attributes = [attribute for attribute in self.required_attributes
+                             if attribute in self.attribute_order[node.tagName]]
+      missing_attributes = [attribute for attribute in required_attributes
+                            if attribute not in attributes]
+
+      for attribute in missing_attributes:
+        logging.error(
+            'Missing attribute "%s" in tag "%s"', attribute, node.tagName)
+      if missing_attributes:
+        missing_attributes_str = (
+            ', '.join('"%s"' % attribute for attribute in missing_attributes))
+        present_attributes = [
+            ' {0}="{1}"'.format(name, value)
+            for name, value in node.attributes.items()]
+        node_str = '<{0}{1}>'.format(node.tagName, ''.join(present_attributes))
+        raise Error(
+            'Missing attributes {0} in tag "{1}"'.format(
+                missing_attributes_str, node_str))
+
+      # Pretty-print the attributes.
       if attributes:
         # Reorder the attributes.
         unrecognized_attributes = (
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0eb13d53..bb6e895d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2221,6 +2221,7 @@
   <int value="166" label="BFSI_INVALID_TITLE"/>
   <int value="167" label="RWH_INVALID_FRAME_TOKEN"/>
   <int value="168" label="RWH_BAD_FRAME_SINK_REQUEST"/>
+  <int value="169" label="RWH_SURFACE_INVARIANTS_VIOLATION"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions" type="int">
@@ -7205,7 +7206,7 @@
   <int value="11" label="Update Recommended"/>
   <int value="12" label="Crypto Password"/>
   <int value="13" label="Safe Browsing Download Feedback"/>
-  <int value="14" label="First Run"/>
+  <int value="14" label="First Run Bubble"/>
   <int value="15" label="Network Share Profile Warning"/>
   <int value="16" label="Conflicting Module"/>
   <int value="17" label="Critical Notification (Upgrade Installed)"/>
@@ -7223,6 +7224,54 @@
   <int value="29" label="Sign In Error"/>
   <int value="30" label="Sign In Email Confirmation"/>
   <int value="31" label="Profile Chooser"/>
+  <int value="32" label="Account Chooser"/>
+  <int value="33" label="Arc App"/>
+  <int value="34" label="Auto Signin First Run"/>
+  <int value="35" label="Bookmark App Confirmation"/>
+  <int value="36" label="Chooser Ui"/>
+  <int value="37" label="Chooser"/>
+  <int value="38" label="Collected Cookies"/>
+  <int value="39" label="Constrained Web"/>
+  <int value="40" label="Content Setting Contents"/>
+  <int value="41" label="Create Chrome Application Shortcut"/>
+  <int value="42" label="Download Danger Prompt"/>
+  <int value="43" label="Download In Progress"/>
+  <int value="44" label="Echo"/>
+  <int value="45" label="Enrollment"/>
+  <int value="46" label="Extension"/>
+  <int value="47" label="Extension Popup Aura"/>
+  <int value="48" label="External Protocol"/>
+  <int value="49" label="External Protocol ChromeOS"/>
+  <int value="50" label="First Run Dialog"/>
+  <int value="51" label="Home Page Undo"/>
+  <int value="52" label="Idle Action Warning"/>
+  <int value="53" label="Import Lock"/>
+  <int value="54" label="Intent Picker"/>
+  <int value="55" label="Invert"/>
+  <int value="56" label="Java Script"/>
+  <int value="57" label="Java Script App Modal X11"/>
+  <int value="58" label="Login Handler"/>
+  <int value="59" label="Manage Passwords"/>
+  <int value="60" label="Media Galleries"/>
+  <int value="61" label="Multiprofiles Intro"/>
+  <int value="62" label="Multiprofiles Session Aborted"/>
+  <int value="63" label="Native Container"/>
+  <int value="64" label="Network Config"/>
+  <int value="65" label="Permissions"/>
+  <int value="66" label="Platform Keys Certificate Selector"/>
+  <int value="67" label="Platform Verification"/>
+  <int value="68" label="Proximity Auth Error"/>
+  <int value="69" label="Request Pin"/>
+  <int value="70" label="SSL Client Certificate Selector"/>
+  <int value="71" label="Simple Message Box"/>
+  <int value="72" label="Tab Modal Confirm"/>
+  <int value="73" label="Task Manager"/>
+  <int value="74" label="Teleport Warning"/>
+  <int value="75" label="User Manager"/>
+  <int value="76" label="User Manager Profile"/>
+  <int value="77" label="Validation Message"/>
+  <int value="78" label="Web Share Target Picker"/>
+  <int value="79" label="Zoom"/>
 </enum>
 
 <enum name="DidNavigateToAd" type="int">
@@ -11049,6 +11098,7 @@
   <int value="405" label="FILE_MANAGER_PRIVATE_ON_APPS_UPDATED"/>
   <int value="406" label="ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_START"/>
   <int value="407" label="ACCESSIBILITY_PRIVATE_ON_TWO_FINGER_TOUCH_STOP"/>
+  <int value="408" label="MEDIA_PERCEPTION_PRIVATE_ON_MEDIA_PERCEPTION"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult" type="int">
@@ -12272,6 +12322,9 @@
   <int value="1171" label="AUTOTESTPRIVATE_GETPLAYSTORESTATE"/>
   <int value="1172" label="AUTOTESTPRIVATE_SETPLAYSTOREENABLED"/>
   <int value="1173" label="APP_CURRENTWINDOWINTERNAL_SETACTIVATEONPOINTER"/>
+  <int value="1174" label="MEDIAPERCEPTIONPRIVATE_GETSTATE"/>
+  <int value="1175" label="MEDIAPERCEPTIONPRIVATE_SETSTATE"/>
+  <int value="1176" label="MEDIAPERCEPTIONPRIVATE_GETDIAGNOSTICS"/>
 </enum>
 
 <enum name="ExtensionIconState" type="int">
@@ -12698,6 +12751,7 @@
   <int value="201" label="kNetworkingOnc"/>
   <int value="202" label="kVirtualKeyboard"/>
   <int value="203" label="kNetworkingCastPrivate"/>
+  <int value="204" label="kMediaPerceptionPrivate"/>
 </enum>
 
 <enum name="ExtensionServiceVerifyAllSuccess" type="int">
@@ -12774,6 +12828,8 @@
   <int value="31" label="ERROR_SERIALIZING_CATALOG"/>
   <int value="32" label="ERROR_SAVING_CATALOG"/>
   <int value="33" label="CRX_HASH_VERIFICATION_FAILED"/>
+  <int value="34" label="CRX_FILE_IS_DELTA_UPDATE"/>
+  <int value="35" label="CRX_EXPECTED_HASH_INVALID"/>
 </enum>
 
 <enum name="ExternalDeviceAction" type="int">
@@ -13887,8 +13943,8 @@
   <int value="958" label="BackspaceNavigatedBackAfterFormInteraction"/>
   <int value="959" label="CSPSourceWildcardWouldMatchExactHost"/>
   <int value="960" label="CredentialManagerGet"/>
-  <int value="961" label="CredentialManagerGetWithUI"/>
-  <int value="962" label="CredentialManagerGetWithoutUI"/>
+  <int value="961" label="CredentialManagerGetMediationOptional"/>
+  <int value="962" label="CredentialManagerGetMediationSilent"/>
   <int value="963" label="CredentialManagerStore"/>
   <int value="964" label="CredentialManagerRequireUserMediation"/>
   <int value="965" label="RequestAutocomplete"/>
@@ -14933,6 +14989,25 @@
   <int value="1973" label="FontShapingNotDefGlyphObserved"/>
   <int value="1974" label="PostMessageOutgoingWouldBeBlockedByConnectSrc"/>
   <int value="1975" label="PostMessageIncomingWouldBeBlockedByConnectSrc"/>
+  <int value="1976" label="PaymentRequestNetworkNameInSupportedMethods"/>
+  <int value="1977" label="CrossOriginPropertyAccess"/>
+  <int value="1978" label="CrossOriginPropertyAccessFromOpener"/>
+  <int value="1979" label="CredentialManagerCreate"/>
+  <int value="1980" label="WebDatabaseCreateDropFTS3Table"/>
+  <int value="1981" label="FieldEditInSecureContext"/>
+  <int value="1982" label="FieldEditInNonSecureContext"/>
+  <int value="1983"
+      label="CredentialManagerCredentialRequestOptionsUnmediated"/>
+  <int value="1984" label="CredentialManagerGetMediationRequired"/>
+  <int value="1985" label="CredentialManagerIdName"/>
+  <int value="1986" label="CredentialManagerPasswordName"/>
+  <int value="1987" label="CredentialManagerAdditionalData"/>
+  <int value="1988" label="CredentialManagerCustomFetch"/>
+  <int value="1989" label="NetInfoRtt"/>
+  <int value="1990" label="NetInfoDownlink"/>
+  <int value="1991" label="ShapeDetection_BarcodeDetectorConstructor"/>
+  <int value="1992" label="ShapeDetection_FaceDetectorConstructor"/>
+  <int value="1993" label="ShapeDetection_TextDetectorConstructor"/>
 </enum>
 
 <enum name="FeedbackSource" type="int">
@@ -15934,15 +16009,14 @@
 </enum>
 
 <enum name="FtpDataConnectionError" type="int">
-  <int value="0">Data connection successful</int>
-  <int value="1">Local firewall blocked the connection</int>
-  <int value="2">Connection timed out</int>
-  <int value="3">
-    Connection has been established, but then got broken (either reset or
-    aborted)
-  </int>
-  <int value="4">Connection has been refused</int>
-  <int value="20">Other kind of error</int>
+  <int value="0" label="Data connection successful"/>
+  <int value="1" label="Local firewall blocked the connection"/>
+  <int value="2" label="Connection timed out"/>
+  <int value="3"
+      label="Connection has been established, but then got broken (either
+             reset or aborted)"/>
+  <int value="4" label="Connection has been refused"/>
+  <int value="20" label="Other kind of error"/>
 </enum>
 
 <enum name="FtpServerType" type="int">
@@ -20917,7 +20991,7 @@
   <int value="1" label="native notifications not supported"/>
   <int value="2" label="missing required capabilities"/>
   <int value="3" label="could not connect to signals"/>
-  <int value="4" label="incompatible spec version"/>
+  <int value="4" label="(DEPRECATED) incompatible spec version"/>
 </enum>
 
 <enum name="LinuxSandboxStatus" type="int">
@@ -21135,17 +21209,6 @@
 </enum>
 
 <enum name="LoginCustomFlags" type="int">
-<!--
-Values in LoginCustomFlags are:  value=(uint32_t)MD5(label).
-This enum is verified by AboutFlagsHistogramTest unit test.
-To add a new entry, add it with any unique value and run test to compute valid
-value. After that run tools/metrics/histograms/validate_format.py to find out
-where the value should be inserted to maintain ordering.
-Don't remove entries when removing a flag, they are still used to decode data
-from previous Chrome versions.
--->
-
-  <summary>Chrome flags that lead to chrome restart on ChromeOS.</summary>
   <int value="-2146613579" label="V8Future:disabled"/>
   <int value="-2143961262" label="D3DVsync:disabled"/>
   <int value="-2143328006"
@@ -21181,6 +21244,7 @@
   <int value="-2062872298" label="market-url-for-testing"/>
   <int value="-2062373123" label="WebPaymentsModifiers:enabled"/>
   <int value="-2058656447" label="ContextualSearchUrlActions:enabled"/>
+  <int value="-2053860791" label="XGEOVisibleNetworks:enabled"/>
   <int value="-2048732429" label="enable-alternative-services"/>
   <int value="-2048679945" label="NTPOfflinePageDownloadSuggestions:disabled"/>
   <int value="-2047832738" label="enable-system-timezone-automatic-detection"/>
@@ -21188,6 +21252,7 @@
   <int value="-2043128632" label="enable-tab-switcher-in-document-mode"/>
   <int value="-2040471724" label="CrOSComponent:disabled"/>
   <int value="-2040115518" label="load-media-router-component-extension"/>
+  <int value="-2036149591" label="FaviconsFromWebManifest:disabled"/>
   <int value="-2033225430" label="NTPMostLikelyFaviconsFromServer:disabled"/>
   <int value="-2029912304" label="StaleWhileRevalidate2:enabled"/>
   <int value="-2025367104" label="enable-material-design-ntp"/>
@@ -21215,6 +21280,7 @@
   <int value="-1956349722" label="disable-smooth-scrolling"/>
   <int value="-1948540128" label="disable-webrtc-hw-encoding (deprecated)"/>
   <int value="-1946595906" label="enable-push-api-background-mode"/>
+  <int value="-1946522787" label="VrCustomTabBrowsing:disabled"/>
   <int value="-1943507605" label="enable-new-video-renderer"/>
   <int value="-1941852572" label="floating-virtual-keyboard"/>
   <int value="-1940806558" label="enable-syncfs-directory-operation"/>
@@ -21362,6 +21428,7 @@
   <int value="-1460462432" label="disable-media-source"/>
   <int value="-1456004000" label="VrShell:disabled"/>
   <int value="-1443796945" label="OfflinePagesSharing:disabled"/>
+  <int value="-1440440375" label="WebVrAutopresent:enabled"/>
   <int value="-1440152291" label="disable-gesture-typing"/>
   <int value="-1438279809" label="GamepadExtensions:disabled"/>
   <int value="-1433719718" label="enable-webrtc-stun-origin"/>
@@ -21424,6 +21491,18 @@
   <int value="-1203742042" label="enable-gesture-selection"/>
   <int value="-1201183153" label="enable-centered-app-list"/>
   <int value="-1197035323" label="ZeroSuggestRedirectToChrome:disabled"/>
+<!--
+Values in LoginCustomFlags are:  value=(uint32_t)MD5(label).
+This enum is verified by AboutFlagsHistogramTest unit test.
+To add a new entry, add it with any unique value and run test to compute valid
+value. After that run tools/metrics/histograms/validate_format.py to find out
+where the value should be inserted to maintain ordering.
+Don't remove entries when removing a flag, they are still used to decode data
+from previous Chrome versions.
+-->
+
+  <summary>Chrome flags that lead to chrome restart on ChromeOS.</summary>
+  <int value="-1195194959" label="XGEOVisibleNetworks:disabled"/>
   <int value="-1190174011" label="enable-hdr"/>
   <int value="-1184904651" label="enable-npapi"/>
   <int value="-1184480269" label="LsdPermissionPrompt:enabled"/>
@@ -21453,6 +21532,7 @@
   <int value="-1107762575" label="enable-data-reduction-proxy-config-client"/>
   <int value="-1102212525" label="enable-tcp-fastopen"/>
   <int value="-1099142083" label="V8Ignition:disabled"/>
+  <int value="-1096595907" label="disable-new-virtual-keyboard-behavior"/>
   <int value="-1084055006" label="disable-web-notification-custom-layouts"/>
   <int value="-1082302549" label="scan-cards-in-web-payments"/>
   <int value="-1078093206" label="ash-debug-shortcuts"/>
@@ -21630,6 +21710,7 @@
   <int value="-418868128" label="enable-experimental-web-platform-features"/>
   <int value="-410852857" label="ImprovedA2HS:disabled"/>
   <int value="-405380243" label="enable-encryption-migration"/>
+  <int value="-400584764" label="ChromeHomeNtpRedesign:enabled"/>
   <int value="-396994784" label="enable-vr-shell"/>
   <int value="-396496344" label="ViewsTaskManager:enabled"/>
   <int value="-395606844" label="enable-site-settings"/>
@@ -21680,6 +21761,7 @@
   <int value="-268357961" label="enable-feature-policy"/>
   <int value="-254887599" label="google-profile-info"/>
   <int value="-250721831" label="AndroidAutofillAccessibility:disabled"/>
+  <int value="-248223420" label="AutofillKeyboardAccessory:disabled"/>
   <int value="-241353344" label="MidiManagerWinrt:disabled"/>
   <int value="-234966279" label="PointerEvent:disabled"/>
   <int value="-234687894"
@@ -21719,6 +21801,7 @@
   <int value="-78035185" label="custom_summary"/>
   <int value="-77872983" label="BookmarkAppsMac:disabled"/>
   <int value="-76631048" label="disable-offline-auto-reload-visible-only"/>
+  <int value="-72455054" label="WebVrAutopresent:disabled"/>
   <int value="-70595606" label="ash-enable-unified-desktop"/>
   <int value="-68877684" label="BackgroundVideoTrackOptimization:enabled"/>
   <int value="-68225452" label="enable-translate-new-ux"/>
@@ -21769,10 +21852,14 @@
   <int value="91938915" label="enable-suggestions-service"/>
   <int value="98134240" label="material-design-ink-drop-animation-speed"/>
   <int value="103932290" label="show-autofill-type-predictions"/>
+  <int value="106840653" label="mus"/>
   <int value="118991027" label="enable-accelerated-fixed-root-background"/>
+  <int value="119185738"
+      label="OmniboxUIExperimentMaxAutocompleteMatches:disabled"/>
   <int value="120429808" label="disable-new-profile-management"/>
   <int value="121684313" label="QuickUnlockPin:enabled"/>
   <int value="121858954" label="enable-supervised-user-safesites"/>
+  <int value="123097915" label="FaviconsFromWebManifest:enabled"/>
   <int value="125581289" label="WebRtcHWVP8Encoding:disabled"/>
   <int value="125934378" label="enable-password-link"/>
   <int value="131881947" label="D3DVsync:enabled"/>
@@ -21790,6 +21877,7 @@
   <int value="203776499" label="enable-virtual-keyboard-overscroll"/>
   <int value="223662457" label="BackgroundLoadingForDownloads:enabled"/>
   <int value="244697230" label="enable-theme-color-in-tabbed-mode"/>
+  <int value="259021228" label="OffMainThreadFetch:disabled"/>
   <int value="262382944" label="GuestViewCrossProcessFrames:disabled"/>
   <int value="266702296" label="disable-plugin-power-saver"/>
   <int value="270267831" label="enable-scripts-require-action"/>
@@ -21905,7 +21993,6 @@
   <int value="644674603" label="DataReductionProxySiteBreakdown:disabled"/>
   <int value="646252875" label="ReadItLaterInMenu:enabled"/>
   <int value="646738320" label="disable-gesture-editing"/>
-  <int value="650602639" label="enable-autofill-keyboard-accessory-view"/>
   <int value="651421878" label="VideoRotateToFullscreen:enabled"/>
   <int value="652561231" label="CustomContextMenu:enabled"/>
   <int value="683410401"
@@ -22044,6 +22131,8 @@
   <int value="1166169237" label="disable-delay-agnostic-aec"/>
   <int value="1167613030" label="enable-permission-action-reporting"/>
   <int value="1174088940" label="enable-wasm"/>
+  <int value="1179013979"
+      label="OmniboxUIExperimentMaxAutocompleteMatches:enabled"/>
   <int value="1179936481" label="enable-android-pay-integration-v1"/>
   <int value="1181056275" label="enable-cloud-backup"/>
   <int value="1183431946" label="v8-cache-options"/>
@@ -22090,6 +22179,7 @@
   <int value="1300282719" label="OfflinePagesBackgroundLoading:enabled"/>
   <int value="1302421166" label="NativeNotifications:disabled"/>
   <int value="1308537004" label="force-pnacl-subzero"/>
+  <int value="1311860720" label="ChromeHomeNtpRedesign:disabled"/>
   <int value="1312025202" label="NTPOfflinePageSuggestions:disabled"/>
   <int value="1314681756" label="NoStatePrefetch:disabled"/>
   <int value="1317562265" label="SeccompSandboxAndroid:disabled"/>
@@ -22102,6 +22192,7 @@
   <int value="1359972809" label="enable-gesture-deletion"/>
   <int value="1361047396" label="disable-click-delay"/>
   <int value="1361073386" label="ContentSuggestionsNotifications:enabled"/>
+  <int value="1363136936" label="VrCustomTabBrowsing:enabled"/>
   <int value="1367529437" label="NTPAssetDownloadSuggestions:enabled"/>
   <int value="1367671275" label="enable-proximity-auth-proximity-detection"/>
   <int value="1371092708" label="disable-desktop-capture-picker-old-ui"/>
@@ -22199,6 +22290,7 @@
   <int value="1733390925" label="force-enable-stylus-tools"/>
   <int value="1747279677" label="disable-delegated-renderer"/>
   <int value="1752168018" label="enable-stale-while-revalidate"/>
+  <int value="1762320532" label="AutofillKeyboardAccessory:enabled"/>
   <int value="1766676896" label="affiliation-based-matching:disabled"/>
   <int value="1772454319" label="enable-storage-manager"/>
   <int value="1775475563" label="malware-interstitial-v3"/>
@@ -22210,7 +22302,6 @@
   <int value="1785093465" label="enable-document-passive-event-listeners"/>
   <int value="1786229999" label="disable-md-downloads"/>
   <int value="1786386775" label="TranslateCompactUI:disabled"/>
-  <int value="1791904609" label="disable-autofill-keyboard-accessory-view"/>
   <int value="1803465156" label="enable-zero-suggest-most-visited"/>
   <int value="1809940714" label="SpeculativeLaunchServiceWorker:disabled"/>
   <int value="1812368073" label="enable-new-app-list-mixer"/>
@@ -22265,6 +22356,7 @@
   <int value="1951466218" label="enable-data-reduction-proxy-lite-page"/>
   <int value="1955677113" label="trace-export-events-to-etw"/>
   <int value="1958387645" label="ScanCardsInWebPayments:enabled"/>
+  <int value="1959148757" label="OffMainThreadFetch:enabled"/>
   <int value="1960169775" label="NewPhotoPicker:disabled"/>
   <int value="1961425320" label="force-qtkit"/>
   <int value="1964816410" label="AndroidPayIntegrationV2:enabled"/>
@@ -25610,34 +25702,96 @@
 
   <int value="0" label="Unknown (not expected to be recorded)"/>
   <int value="1" label="Loaded (not expected to be recorded)"/>
-  <int value="2" label="Saved"/>
-  <int value="3" label="RequestCoordinator canceled"/>
-  <int value="4" label="Loading canceled"/>
-  <int value="5" label="Loading failed (retryable)"/>
-  <int value="6" label="Save failed"/>
-  <int value="7" label="Foreground transition canceled"/>
-  <int value="8" label="RequestCoordinator timed-out"/>
+  <int value="2" label="Saved">The attempt finished successfully.</int>
+  <int value="3" label="RequestCoordinator canceled">
+    The attempt was canceled by the request coordinator. This is triggered when
+    the user cancels an in-flight offlining attempt, and will always result in
+    BackgroundSavePageResult::USER_CANCELED.
+  </int>
+  <int value="4" label="Loading canceled">
+    Loading was canceled by various pre-render monitoring. These include when
+    window.open was called, when audio is detected, etc.
+  </int>
+  <int value="5" label="Loading failed (retriable)">
+    The attempt resulted in a retriable loading failure. This may be because we
+    found a network error or a page error (i.e. 404 pages will also result in an
+    Loading Failed). Because fickle networks make network errors unreliable, an
+    incorrectly typed URL will also result in retriable loading failure.
+  </int>
+  <int value="6" label="Save failed">
+    The attempt failed because save did not succeed.
+  </int>
+  <int value="7" label="Foreground transition canceled">
+    The attempt failed because chrome is now operating in the foreground on a
+    svelte device.
+  </int>
+  <int value="8" label="RequestCoordinator timed-out">
+    The attempt failed because the particular attempt ran out of time.
+  </int>
   <int value="9" label="Loading not started (deprecated 1/2017)"/>
-  <int value="10" label="Loading failed (non-retryable)"/>
-  <int value="11" label="Loading failed (don't start next request)"/>
-  <int value="12" label="Loading not accepted"/>
-  <int value="13" label="Queue update failed"/>
-  <int value="14" label="Background scheduler canceled processing"/>
-  <int value="15" label="Saved after timeout on last retry"/>
+  <int value="10" label="Loading failed (non-retriable)">
+    The attempt resulted in a non-retriable loading error. This is mostly
+    deprecated as of 4/2017 because a fickle network and a good page might
+    result in the same errors as a bad page with invalid URL.
+  </int>
+  <int value="11" label="Loading failed (don't start next request)">
+    The attempt resulted in a loading failure but we've reason to believe we
+    shouldn't try something else for a little while: i.e. we failed because a
+    renderer crashed or we got INTERNET_DISCONNECTED as the network error.
+  </int>
+  <int value="12" label="Loading not accepted">
+    The offliner was asked to attempt something when it's not ready.
+  </int>
+  <int value="13" label="Queue update failed">
+    The request coordinator failed updating the status of the request in the
+    queue. The attempt is aborted.
+  </int>
+  <int value="14" label="Background scheduler canceled processing">
+    Called when the background scheduler stops the processing.
+  </int>
+  <int value="15" label="Saved after timeout on last retry">
+    The attempt succeeded, but only as a result of snapshotting on the last
+    retry and we have already received DocumentAvailableInMainFrame. Note that
+    if we're already in the middle of snapshotting, we will record SAVED. The
+    quality of the page is presumed to be lower.
+  </int>
+  <int value="16" label="Browser killed">
+    The browser was killed for reasons such as OOM, swiped out, or crashed.
+  </int>
 </enum>
 
 <enum name="OfflinePagesBackgroundSavePageResult" type="int">
 <!-- Generated from components/offline_pages/core/background/request_notifier.h -->
 
-  <int value="0" label="Success"/>
-  <int value="1" label="Loading failure"/>
-  <int value="2" label="Loading canceled"/>
-  <int value="3" label="Foreground canceled"/>
-  <int value="4" label="Save failed"/>
-  <int value="5" label="Expired"/>
-  <int value="6" label="Retry count exceeded"/>
-  <int value="7" label="Start count exceeded"/>
-  <int value="8" label="Removed"/>
+  <int value="0" label="Success">Request was completed successfully.</int>
+  <int value="1" label="Loading failure">
+    Request failed because a non-recoverable loading failure occurred.
+  </int>
+  <int value="2" label="Loading canceled">
+    Loading was canceled by various pre-renderer monitoring. This is not used
+    anywhere.
+  </int>
+  <int value="3" label="Foreground canceled">
+    Loading was canceled by chrome moving to the foreground on a svelte device.
+  </int>
+  <int value="4" label="Save failed">
+    Loading failed because we failed saving the page.
+  </int>
+  <int value="5" label="Expired">
+    Request failed because it expired before we were able to get to it.
+  </int>
+  <int value="6" label="Retry count exceeded">
+    Request failed because we exceeded the maximum number of retries.
+  </int>
+  <int value="7" label="Start count exceeded">
+    Request failed because we exceeded the maximum number of starts. Each start
+    may have completed (resulting in a load error or one of the other
+    per-attempt statuses) or chrome may have died before the attempt's result
+    was recorded.
+  </int>
+  <int value="8" label="User canceled">
+    The request was removed by the user.
+  </int>
 </enum>
 
 <enum name="OfflinePagesCctApiPrerenderAllowedStatus" type="int">
@@ -25693,17 +25847,40 @@
 </enum>
 
 <enum name="OfflinePagesSavePageResult" type="int">
-  <int value="0" label="Success"/>
-  <int value="1" label="Cancelled"/>
-  <int value="2" label="Device full"/>
-  <int value="3" label="Content unavailable"/>
-  <int value="4" label="Archive creation failed"/>
-  <int value="5" label="Store failure"/>
-  <int value="6" label="Already exists"/>
-  <int value="7" label="Skipped"/>
-  <int value="8" label="Security certificate error"/>
-  <int value="9" label="Error page detected"/>
-  <int value="10" label="Interstitial page detected"/>
+  <int value="0" label="Success">Page was saved successfully.</int>
+  <int value="1" label="Cancelled">Page save was cancelled in the interim.</int>
+  <int value="2" label="Device full">
+    Save operation failed because device storage was full.
+  </int>
+  <int value="3" label="Content unavailable">
+    A save operation was called with an invalid archiver.
+  </int>
+  <int value="4" label="Archive creation failed">
+    Either something went wrong with the save operation, or the url we saved was
+    different from the one we passed in.
+  </int>
+  <int value="5" label="Store failure">
+    The SQL operation to add the page to the offline store failed.
+  </int>
+  <int value="6" label="Already exists">
+    A page with this ID already exists.
+  </int>
+  <int value="7" label="Skipped">
+    Certain pages like file URL or NTP will not be saved because they're already
+    available offline.
+  </int>
+  <int value="8" label="Security certificate error">
+    Save operation failed because the page resulted in a security certificate
+    error.
+  </int>
+  <int value="9" label="Error page detected">
+    Save operation failed because an error page (i.e. offline dino page) was
+    detected.
+  </int>
+  <int value="10" label="Interstitial page detected">
+    Save operation failed because an interstitial page (i.e. page warning of
+    expired certificates or improper dev signatures) was detected.
+  </int>
 </enum>
 
 <enum name="OfflinePagesSharedPageWasOffline" type="int">
@@ -26369,6 +26546,13 @@
   <int value="5" label="Successful first layout (backgrounded)"/>
 </enum>
 
+<enum name="PageLoadMetricsAMPViewType" type="int">
+  <int value="0" label="None"/>
+  <int value="1" label="AMP Cache"/>
+  <int value="2" label="Google Search AMP Viewer"/>
+  <int value="3" label="Google News AMP Viewer"/>
+</enum>
+
 <enum name="PageLoadTimingStatus" type="int">
   <summary>Status of PageLoadTimings received from the render process</summary>
   <int value="0" label="Valid"/>
@@ -26583,6 +26767,11 @@
       label="Remaining download time does not meet the requirement."/>
 </enum>
 
+<enum name="ParentFrameKnown" type="int">
+  <int value="0" label="Parent Frame Not Known"/>
+  <int value="1" label="Parent Frame Known"/>
+</enum>
+
 <enum name="ParsedCookieStatus" type="int">
   <obsolete>
     Deprecated as of 9/2013. Experiment to measure control characters in cookies
@@ -27210,11 +27399,13 @@
   <int value="4" label="Matched whitelist"/>
   <int value="5" label="Response already cached"/>
   <int value="6" label="DEPRECATED: Not extended reporting user"/>
-  <int value="7" label="DEPRECATED: Incognito"/>
+  <int value="7" label="Disabled due to incognito"/>
   <int value="8" label="Request malformed"/>
   <int value="9" label="Fetch failed"/>
   <int value="10" label="Response malformed"/>
   <int value="11" label="Service destroyed"/>
+  <int value="12" label="Disabled due to feature disabled"/>
+  <int value="13" label="Disabled due to user population"/>
 </enum>
 
 <enum name="PasswordProtectionVerdict" type="int">
@@ -29770,6 +29961,14 @@
   <int value="1" label="Increment"/>
 </enum>
 
+<enum name="RemoteHungProcessTerminateReason" type="int">
+  <int value="1" label="Terminate accepted by user"/>
+  <int value="2" label="No visible windows found"/>
+  <int value="3" label="Retry attempts to notify remote process exceeded"/>
+  <int value="4" label="Failed to write message to socket"/>
+  <int value="5" label="Failed to read ACK message from socket"/>
+</enum>
+
 <enum name="RemotePlaybackDeviceType" type="int">
   <int value="0" label="Cast Generic Media Player"/>
   <int value="1" label="Cast YouTube Player"/>
@@ -29786,6 +29985,25 @@
   <int value="6" label="Unknown media type"/>
 </enum>
 
+<enum name="RemoteProcessInteractionResult" type="int">
+  <int value="0" label="Terminate succeeded"/>
+  <int value="1" label="Terminate failed"/>
+  <int value="2" label="Remote process not found"/>
+  <int value="3" label="Terminate wait timeout"/>
+  <int value="4" label="Error occured during remote process notification"/>
+  <int value="5" label="Not enough permissions to terminate"/>
+  <int value="6" label="Remote process is shutting down"/>
+  <int value="7" label="User accepted profile unlock"/>
+  <int value="8"
+      label="User accepted profile unlock prior to remote process kill"/>
+  <int value="9" label="Remote process is the same browser instance"/>
+  <int value="10"
+      label="Found the same browser instance prior to remote process kill"/>
+  <int value="11" label="Failed to extract pid from lock file path"/>
+  <int value="12" label="Invalid lock file"/>
+  <int value="13" label="Orphaned lock file"/>
+</enum>
+
 <enum name="RemotingStartTrigger" type="int">
   <int value="0" label="Unknown start trigger"/>
   <int value="1" label="Entered fullscreen"/>
@@ -31179,6 +31397,7 @@
   <int value="1" label="Failed"/>
   <int value="2" label="No Answer"/>
   <int value="3" label="Received Answer"/>
+  <int value="4" label="Received Answer - Too Large"/>
 </enum>
 
 <enum name="SearchEngine" type="int">
@@ -33227,9 +33446,7 @@
   <int value="11" label="SELF_SIGNED: The cert is self-signed">
     This cause is recorded only for CERT_AUTHORITY_INVALID errors.
   </int>
-  <int value="12" label="EXPIRED_RECENTLY: Cert expired within last 28 days.">
-
-  </int>
+  <int value="12" label="EXPIRED_RECENTLY: Cert expired within last 28 days."/>
   <int value="13" label="LIKELY_SAME_DOMAIN: (Deprecated)">
     (Deprecated in favor of LIKELY_SAME_DOMAIN2)
   </int>
@@ -33549,6 +33766,9 @@
   <int value="4" label="Frame detached"/>
   <int value="5" label="By context menu"/>
   <int value="6" label="DOM mutation after XHR"/>
+  <int value="7" label="Provisionally saved form on start provisional load"/>
+  <int value="8" label="Filled form on start provisional load"/>
+  <int value="9" label="Filled input elements on start provisional load"/>
 </enum>
 
 <enum name="SubresourceFilterActions" type="int">
@@ -33556,14 +33776,14 @@
   <int value="1" label="UI Shown"/>
   <int value="2" label="Details shown"/>
   <int value="3" label="Learn more clicked"/>
-  <int value="4" label="Content setting blocked from UI"/>
-  <int value="5" label="Content setting allowed"/>
-  <int value="6" label="Content setting blocked"/>
-  <int value="7" label="Content setting allowed (global)"/>
-  <int value="8" label="Content setting blocked (global)"/>
-  <int value="9" label="Content setting wildcard update"/>
+  <int value="4" label="Content setting: allowed from UI"/>
+  <int value="5" label="Content setting: blocked"/>
+  <int value="6" label="Content setting: allowed"/>
+  <int value="7" label="Content setting: blocked (global)"/>
+  <int value="8" label="Content setting: allowed (global)"/>
+  <int value="9" label="Content setting: wildcard update (Deprecated)"/>
   <int value="10" label="UI Suppressed (Smart Logic)"/>
-  <int value="11" label="Content setting blocked while UI suppressed"/>
+  <int value="11" label="Content setting: allowed while UI suppressed"/>
 </enum>
 
 <enum name="SubresourceFilterActivationDecision" type="int">
@@ -34796,7 +35016,7 @@
 <enum name="TranslateCompactUIEvent" type="int">
   <int value="0" label="Infobar impression"/>
   <int value="1" label="Tab language clicked"/>
-  <int value="2" label="Infobar closed"/>
+  <int value="2" label="Translate services declined"/>
   <int value="3" label="Options menu clicked"/>
   <int value="4" label="More languages clicked"/>
   <int value="5" label="Language picked from more languages"/>
@@ -34813,6 +35033,12 @@
   <int value="16" label="Cancel clicked on always translate snackbar"/>
   <int value="17" label="Cancel clicked on never translate this site snackbar"/>
   <int value="18" label="Cancel clicked on never translate snackbar"/>
+  <int value="19" label="Undo always translate"/>
+  <int value="20" label="Infobar closed"/>
+  <int value="21" label="Auto-always translate snackbar impression"/>
+  <int value="22" label="Auto-never translate snackbar impression"/>
+  <int value="23" label="Cancel clicked on auto-always translate snackbar"/>
+  <int value="24" label="Cancel clicked on auto-never translate snackbar"/>
 </enum>
 
 <enum name="TranslateError" type="int">
@@ -36091,6 +36317,7 @@
   <int value="1" label="Device no longer in range."/>
   <int value="2" label="Not found"/>
   <int value="3" label="No services"/>
+  <int value="4" label="Device disconnected"/>
 </enum>
 
 <enum name="WebBluetoothRequestDeviceOutcome" type="int">
@@ -36429,6 +36656,7 @@
   <int value="0" label="Closed by system"/>
   <int value="1" label="Closed by user"/>
   <int value="2" label="Clicked"/>
+  <int value="3" label="Manual navigation to the landing page"/>
 </enum>
 
 <enum name="WebUsbPermissionRevoked" type="int">
@@ -36601,6 +36829,8 @@
   <int value="6" label="Windows 8.1"/>
   <int value="7" label="Windows 10"/>
   <int value="8" label="Windows 10 TH2"/>
+  <int value="9" label="Windows 10 RS1"/>
+  <int value="10" label="Windows 10 RS2"/>
 </enum>
 
 <enum name="WindowType" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3862a2a..c9ff880 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -423,6 +423,23 @@
   </summary>
 </histogram>
 
+<histogram name="ActivityTracker.Collect.UncleanShutdownCount" units="count">
+  <owner>manzagop@chromium.org</owner>
+  <summary>
+    Number of unclean shutdowns, as derived from the stability instrumentation.
+    Logged each time stability file collection is performed.
+  </summary>
+</histogram>
+
+<histogram name="ActivityTracker.Collect.UncleanSystemCount" units="count">
+  <owner>manzagop@chromium.org</owner>
+  <summary>
+    Number of unclean shutdowns that can potentially be attributed to system
+    instability. This should be smaller or equal to UncleanShutdownCount. Logged
+    each time stability file collection is performed.
+  </summary>
+</histogram>
+
 <histogram name="ActivityTracker.Collect.WriteDumpStatus"
     enum="ActivityTrackerWriteDumpStatus">
   <owner>manzagop@chromium.org</owner>
@@ -2379,6 +2396,17 @@
   <summary>The wallpaper type. Recorded at user login.</summary>
 </histogram>
 
+<histogram name="Ash.Window.AnimationSmoothness.CrossFade" units="%">
+  <owner>wutao@chromium.org</owner>
+  <summary>
+    Relative smoothness of cross fade animation when setting window bounds. 100%
+    represents ideally smooth 60 frames per second. 50% represents when only 30
+    frames per second is achieved during the animations. 0% should not happen.
+    This metric is recorded exactly once when SetBoundsDirectCrossFade is
+    called, such as when window is maximized.
+  </summary>
+</histogram>
+
 <histogram name="Ash.WindowCycleController.CycleTime" units="ms">
   <owner>varkha@chromium.org</owner>
   <owner>tbuckley@google.com</owner>
@@ -4790,7 +4818,7 @@
 </histogram>
 
 <histogram name="Blink.BudgetAPI.QueryBudget" units="budget">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     Whenever the Budget API framework receives a query for the current budget,
     this records the total budget available to the origin, which is an internal
@@ -4803,7 +4831,7 @@
 </histogram>
 
 <histogram name="Blink.BudgetAPI.Reserve" enum="BooleanSuccess">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     Whenever the Budget API framework receives a request to reserve budget for a
     future background operation, this records whether the reserve request
@@ -5361,6 +5389,16 @@
   </details>
 </histogram>
 
+<histogram name="Blink.UseCounter.Extensions.Features" enum="FeatureObserver">
+  <owner>rbyers@chromium.org</owner>
+  <summary>
+    Count of how many page loads use various features for pages with a
+    chrome-extension:// URL only. The PageVisits bucket is incremented for each
+    page load, and the other buckets incremented at most once per PageVisit via
+    the WebCore::UserCounter class.
+  </summary>
+</histogram>
+
 <histogram name="Blink.UseCounter.Features" enum="FeatureObserver">
   <owner>rbyers@chromium.org</owner>
   <summary>
@@ -7093,6 +7131,61 @@
   </summary>
 </histogram>
 
+<histogram name="Chrome.ProcessSingleton.RemoteHungProcessTerminateReason"
+    enum="RemoteHungProcessTerminateReason">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>The reason of remote hang processes termination.</summary>
+</histogram>
+
+<histogram name="Chrome.ProcessSingleton.RemoteProcessInteractionResult"
+    enum="RemoteProcessInteractionResult">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    Used to send the result of interaction with remote process as histograms in
+    case when remote process influences on start.
+  </summary>
+</histogram>
+
+<histogram name="Chrome.ProcessSingleton.TerminateProcessErrorCode.Posix"
+    enum="OSAgnosticErrno">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    The error code of remote process termination on Posix in case when remote
+    process hung.
+  </summary>
+</histogram>
+
+<histogram name="Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows"
+    enum="WinGetLastError">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    The error code of remote process termination on Windows in case when remote
+    process hung.
+  </summary>
+</histogram>
+
+<histogram name="Chrome.ProcessSingleton.TerminateProcessTime" units="ms">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    Time it takes from TerminateProcess call to the moment when we stop waiting
+    for remote process switches to signal state.
+  </summary>
+</histogram>
+
+<histogram name="Chrome.ProcessSingleton.TerminationWaitErrorCode.Windows"
+    enum="WinGetLastError">
+  <owner>aseren@yandex-team.ru</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    The error code of wating for remote process termination on Windows.
+  </summary>
+</histogram>
+
 <histogram name="Chrome.ProcessSingleton.TimeToCreate" units="ms">
   <owner>gab@chromium.org</owner>
   <summary>
@@ -14285,6 +14378,16 @@
   </summary>
 </histogram>
 
+<histogram name="Download.Parallelizable.DownloadTime" units="ms">
+  <owner>xingliu@chromium.org</owner>
+  <summary>The download time for a parallelizable download.</summary>
+</histogram>
+
+<histogram name="Download.Parallelizable.FileSize" units="KB">
+  <owner>xingliu@chromium.org</owner>
+  <summary>The download size of a parallelizable download.</summary>
+</histogram>
+
 <histogram base="true" name="Download.ParallelizableDownloadBandwidth"
     units="bytes/second">
   <owner>qinmin@chromium.org</owner>
@@ -16521,7 +16624,7 @@
   </summary>
 </histogram>
 
-<histogram name="Event.Latency.EndToEnd.Key" units="ms">
+<histogram name="Event.Latency.EndToEnd.KeyPress" units="ms">
   <owner>tdresser@chromium.org</owner>
   <owner>input-dev@chromium.org</owner>
   <summary>
@@ -20670,11 +20773,17 @@
 </histogram>
 
 <histogram name="Extensions.StartupDelay" units="ms">
+  <obsolete>
+    This has not been recorded since at least mid-2013.
+  </obsolete>
   <owner>asargent@chromium.org</owner>
   <summary>The time one extension delays network requests at startup.</summary>
 </histogram>
 
 <histogram name="Extensions.StartupDelay_Total" units="ms">
+  <obsolete>
+    This has not been recorded since at least mid-2013.
+  </obsolete>
   <owner>rdevlin.cronin@chromium.org</owner>
   <summary>
     The total time extensions delay network requests at startup.
@@ -21759,7 +21868,7 @@
 </histogram>
 
 <histogram name="GCM.PendingConnectionEventsAtShutdown" units="events">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     Number of connection events which have not been sent to GCM. This is
     recorded only at the time of shutdown to capture the events which are being
@@ -26540,6 +26649,23 @@
   <summary>Records the autoplay source of audios.</summary>
 </histogram>
 
+<histogram name="Media.Audio.Autoplay.Attribute.WaitTime" units="ms">
+  <owner>hubbe@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records time from load starts until audio starts based on autoplay
+    attribute.
+  </summary>
+</histogram>
+
+<histogram name="Media.Audio.Autoplay.PlayMethod.WaitTime" units="ms">
+  <owner>hubbe@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records time from load starts until audio starts based on play method.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.Capture.CallbackError" enum="BooleanError">
   <obsolete>
     Deprecated as of 02/2017.
@@ -26694,7 +26820,7 @@
   <owner>henrika@chromium.org</owner>
   <summary>
     Indicates if audio capturing did start after stream startup was requested.
-    Sampled once 5 seconds after a stream has been asked to start.
+    Sampled once, a few seconds after a stream has been asked to start.
   </summary>
 </histogram>
 
@@ -28699,6 +28825,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.UnderflowDuration.EME" units="ms">
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    The amount of time taken to leave the underflow state (i.e. resume playback)
+    for Encrypted Media Extensions (EME) based playbacks.
+  </summary>
+</histogram>
+
 <histogram name="Media.UnderflowDuration.MSE" units="ms">
   <owner>dalecurtis@chromium.org</owner>
   <summary>
@@ -28755,6 +28889,15 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Video.Autoplay.Attribute.WaitTime" units="ms">
+  <owner>hubbe@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records time from load starts until video starts based on autoplay
+    attribute.
+  </summary>
+</histogram>
+
 <histogram name="Media.Video.Autoplay.Muted" enum="AutoplaySource">
   <owner>avayvod@chromium.org</owner>
   <owner>mlamouri@chromium.org</owner>
@@ -28821,6 +28964,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Video.Autoplay.PlayMethod.WaitTime" units="ms">
+  <owner>hubbe@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records time from load starts until video starts based on play method.
+  </summary>
+</histogram>
+
 <histogram name="Media.Video.FullscreenOrientationLock.LockResult"
     enum="VideoFullscreenOrientationLockResult">
   <owner>mlamouri@chromium.org</owner>
@@ -29403,6 +29554,15 @@
   <summary>Result of a request to join a route.</summary>
 </histogram>
 
+<histogram name="MediaRouter.Provider.RouteControllerCreationOutcome"
+    enum="BooleanSuccess">
+  <owner>takumif@chromium.org</owner>
+  <summary>
+    Records whether the Media Route Provider succeeded or failed to create a
+    controller for a media route.
+  </summary>
+</histogram>
+
 <histogram name="MediaRouter.Provider.TerminateRoute.Result"
     enum="MediaRouteProviderResult">
   <owner>mfoltz@chromium.org</owner>
@@ -30836,7 +30996,7 @@
   </summary>
 </histogram>
 
-<histogram name="Mobile.DefaultBrowser.BrowserCount">
+<histogram base="true" name="Mobile.DefaultBrowser.BrowserCount">
 <!-- Name completed by histogram_suffixes name="Mobile.DefaultBrowser.Type" -->
 
   <owner>dtrainor@chromium.org</owner>
@@ -30851,6 +31011,14 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Mobile.DefaultBrowser.SystemBrowserCount">
+<!-- Name completed by histogram_suffixes
+    name="Mobile.DefaultBrowser.SystemDefaultBrowser.Type" -->
+
+  <owner>dtrainor@chromium.org</owner>
+  <summary>Android: The number of system installed browsers.</summary>
+</histogram>
+
 <histogram name="Mobile.SystemNotification.Blocked"
     enum="SystemNotificationType">
   <owner>dtrainor@chromium.org</owner>
@@ -31264,6 +31432,19 @@
   </summary>
 </histogram>
 
+<histogram name="MojoLevelDBEnv.IOError" enum="LevelDBIOErrorMethods">
+  <owner>mek@chromium.org</owner>
+  <summary>Methods where leveldb's Mojo environment has IO errors.</summary>
+</histogram>
+
+<histogram name="MojoLevelDBEnv.IOError.BFE" enum="PlatformFileError">
+  <owner>mek@chromium.org</owner>
+  <summary>
+    Errors (base::File::Error) encountered by a single leveldb method in
+    leveldb's Mojo environment.
+  </summary>
+</histogram>
+
 <histogram name="Mouse.PointerSensitivity.Changed" enum="PointerSensitivity">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -46213,6 +46394,9 @@
 
 <histogram name="Omnibox.ProgressBarBreakPointUpdateCount"
     units="break point updates">
+  <obselete>
+    Obselete 05/16/2017. Data is unused (crbug.com/719801).
+  </obselete>
   <owner>kkimlabs@chromium.org</owner>
   <summary>
     The number of progress bar break point updates from page load started to
@@ -46221,6 +46405,9 @@
 </histogram>
 
 <histogram name="Omnibox.ProgressBarUpdateCount" units="frame updates">
+  <obselete>
+    Obselete 05/16/2017. Data is unused (crbug.com/719801).
+  </obselete>
   <owner>kkimlabs@chromium.org</owner>
   <summary>
     The number of progress bar frame updates from page load started to page load
@@ -47591,6 +47778,30 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.Ads.Google.ParentExistsForSubFrame"
+    enum="ParentFrameKnown">
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    Records whether or not a parent frame is found for a subframe that finishes
+    navigating.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Clients.Ads.Google.ResourceTypeWhenNoFrameFound"
+    enum="ContentResourceType2">
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    Records the content::ResourceType when a resource finishes loading but the
+    ads metrics aren't aware of a committed frame for the resource.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Clients.AMP.SameDocumentView"
+    enum="PageLoadMetricsAMPViewType">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>Count of same document page views for AMP pages.</summary>
+</histogram>
+
 <histogram
     name="PageLoad.Clients.DataReductionProxy.Experimental.Bytes.Network.CompressionRatio"
     units="%">
@@ -49139,6 +49350,17 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.AcceptedSaveUpdateSubmissionIndicatorEvent"
+    enum="SubmissionIndicatorEvent">
+  <owner>dvadym@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    The type of event that the Password Manager used for detecting a password
+    form submission when saving or updating a password. Recorded each time a
+    user accepts a password save/update prompt.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.AccountChooserDialog"
     enum="AccountChooserDismissalReason">
   <obsolete>
@@ -49494,6 +49716,10 @@
 </histogram>
 
 <histogram name="PasswordManager.GetMediated" enum="CredentialManagerGetResult">
+  <obsolete>
+    Deprecated as of 05/2017. This metric has been replaced by
+    PasswordManager.MediationOptional.
+  </obsolete>
   <owner>vasilii@chromium.org</owner>
   <summary>
     Tracks result of navigator.credentials.get() with unmediated=false. That is
@@ -49503,6 +49729,10 @@
 
 <histogram name="PasswordManager.GetUnmediated"
     enum="CredentialManagerGetResult">
+  <obsolete>
+    Deprecated as of 05/2017. This metric has been replaced by
+    PasswordManager.MediationSilent.
+  </obsolete>
   <owner>vasilii@chromium.org</owner>
   <summary>
     Tracks result of navigator.credentials.get() with unmediated=true. That is
@@ -49628,6 +49858,37 @@
   <summary>An error on LoginDatabase initialization.</summary>
 </histogram>
 
+<histogram name="PasswordManager.MediationOptional"
+    enum="CredentialManagerGetResult">
+  <owner>jdoerrie@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Tracks result of navigator.credentials.get() with
+    mediation=&quot;optional&quot;. That is the result of account chooser.
+  </summary>
+</histogram>
+
+<histogram name="PasswordManager.MediationRequired"
+    enum="CredentialManagerGetResult">
+  <owner>jdoerrie@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Tracks result of navigator.credentials.get() with
+    mediation=&quot;required&quot;. That is the result of forced account
+    chooser.
+  </summary>
+</histogram>
+
+<histogram name="PasswordManager.MediationSilent"
+    enum="CredentialManagerGetResult">
+  <owner>jdoerrie@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Tracks result of navigator.credentials.get() with
+    mediation=&quot;silent&quot;. That is the result of auto sign-in.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.MultiAccountPasswordUpdateAction"
     enum="MultiAccountUpdateBubbleUserAction">
   <owner>dvadym@chromium.org</owner>
@@ -49692,6 +49953,10 @@
 
 <histogram name="PasswordManager.PasswordReuse.MainFrameMatchCsdWhitelist"
     enum="Boolean">
+  <obsolete>
+    Deprecated as of May 17 2017. Replaced by
+    PasswordProtection.RequestOutcome.ProtectedPasswordEntry.
+  </obsolete>
   <owner>dvadym@chromium.org</owner>
   <owner>jialiul@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
@@ -50117,6 +50382,10 @@
 
 <histogram name="PasswordProtection.PasswordReuseEventVerdict"
     enum="PasswordProtectionVerdict">
+  <obsolete>
+    Deprecated since May 12 2017. Replaced by
+    PasswordProtection.Verdict.ProtectedPasswordEntry.
+  </obsolete>
   <owner>jialiul@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -50133,7 +50402,7 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordProtection.RequestOutcome"
+<histogram base="true" name="PasswordProtection.RequestOutcome"
     enum="PasswordProtectionRequestOutcome">
   <owner>jialiul@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
@@ -50146,6 +50415,10 @@
 
 <histogram name="PasswordProtection.UnfamiliarLoginPageVerdict"
     enum="PasswordProtectionVerdict">
+  <obsolete>
+    Deprecated since May 12 2017. Replaced by
+    PasswordProtection.Verdict.PasswordFieldOnFocus.
+  </obsolete>
   <owner>jialiul@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -50153,6 +50426,16 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordProtection.Verdict" enum="PasswordProtectionVerdict">
+  <owner>jialiul@chromium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    Verdict types returned by Safe Browsing server for a password protection
+    request. Request can be triggered when user focuses on a password field or
+    enters a protected password.
+  </summary>
+</histogram>
+
 <histogram
     name="PaymentRequest.CanMakePayment.NotUsed.WithShowEffectOnCompletion"
     enum="PaymentRequestFlowCompletionStatus">
@@ -57268,7 +57551,7 @@
 </histogram>
 
 <histogram name="PushMessaging.BackgroundBudget">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     Whenever a Service Worker receives a push message, this records the budget
     available to the service worker, which is an internal Chrome value for the
@@ -57336,7 +57619,7 @@
 </histogram>
 
 <histogram name="PushMessaging.SESForLowBudgetOrigin">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a Service Worker hits low budget when servicing a push message, this
     records what the Site Engagement Service score is at that time.
@@ -57344,7 +57627,7 @@
 </histogram>
 
 <histogram name="PushMessaging.SESForNoBudgetOrigin">
-  <owner>harkness@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a Service Worker hits zero budget when servicing a push message, this
     records what the Site Engagement Service score is at that time.
@@ -58909,11 +59192,24 @@
   <owner>altimin@chromium.org,alexclarke@chromium.org</owner>
   <summary>
     The number of completed renderer tasks split per task queue type. Used to
-    monitor usage of each type of task queues. Reported each time when task is
+    monitor usage of each type of task queue. Reported each time when task is
     completed.
   </summary>
 </histogram>
 
+<histogram name="RendererScheduler.TaskDurationPerQueueType"
+    enum="RendererSchedulerTaskQueueType" units="ms">
+  <owner>altimin@chromium.org,alexclarke@chromium.org</owner>
+  <summary>
+    Total duration of renderer tasks split per task queue type. Used to monitor
+    usage of each type of task queues. Reported each time when task is completed
+    and current accumulated duration is longer than 1ms.
+
+    This metric is susceptible to problematic outliers and should be analyzed
+    with custom scripts accounting for that rather than from a dashboard.
+  </summary>
+</histogram>
+
 <histogram name="RendererScheduler.TaskQueueManager.DelayedTaskLateness"
     units="ms">
   <owner>alexclarke@chromium.org</owner>
@@ -70350,6 +70646,11 @@
 </histogram>
 
 <histogram name="Stability.Android.PendingMinidumpsOnStartup" units="minidumps">
+  <obsolete>
+    Deprecated in M60. Roughly 50% of Chrome startups that had *any* pending
+    minidumps had at least one pending minidump without any logcat output. About
+    5% had multiple minidumps without any logcat output.
+  </obsolete>
   <owner>isherman@chromium.org</owner>
   <summary>
     The number of un-uploaded minidumps present in the Android Crash Reports
@@ -70362,6 +70663,11 @@
 
 <histogram name="Stability.Android.PendingMinidumpsOnStartup.SansLogcat"
     units="minidumps">
+  <obsolete>
+    Deprecated in M60. Roughly 50% of Chrome startups that had *any* pending
+    minidumps had at least one pending minidump without any logcat output. About
+    5% had multiple minidumps without any logcat output.
+  </obsolete>
   <owner>isherman@chromium.org</owner>
   <summary>
     The number of un-uploaded minidumps present in the Android Crash Reports
@@ -71678,6 +71984,20 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Storage.BytesRead" units="bytes">
+  <owner>michaeln@chromium.org</owner>
+  <summary>
+    The number of bytes read. Recorded on each read.
+  </summary>
+</histogram>
+
+<histogram base="true" name="Storage.BytesWritten" units="bytes">
+  <owner>michaeln@chromium.org</owner>
+  <summary>
+    The number of bytes written. Recorded on each write.
+  </summary>
+</histogram>
+
 <histogram name="Storage.ImportantSites.CBDChosenReason"
     enum="ImportantSitesReason">
   <owner>dmurph@chromium.org</owner>
@@ -71979,6 +72299,15 @@
   </summary>
 </histogram>
 
+<histogram name="SubresourceFilter.PageLoad.FinalURLMatch" units="matches">
+  <owner>melandory@chromium.org</owner>
+  <summary>
+    Records, for each main frame navigation, whether the last URL in the
+    redirect chain matched the Safe Browsing blacklist specified by the
+    histogram suffix.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.Disallowed"
     units="resource loads">
   <owner>pkalinnikov@chromium.org</owner>
@@ -72032,6 +72361,10 @@
 
 <histogram name="SubresourceFilter.PageLoad.RedirectChainMatchPattern"
     enum="SubresourceFilterMatchPattern">
+  <obsolete>
+    Obsolete as of April 2017, since the don't have correct data to record
+    anymore.
+  </obsolete>
   <owner>melandory@chromium.org</owner>
   <summary>
     For each main frame navigation, records a pattern that indicates which URLs
@@ -74480,13 +74813,13 @@
 </histogram>
 
 <histogram name="Tab.NewTabOnload" units="ms">
-  <owner>lliabraa@chromium.org</owner>
-  <owner>beaudoin@chromium.org</owner>
+  <owner>treib@chromium.org</owner>
   <summary>
     The time for the new tab page to fire the &quot;load&quot; event. Note: This
-    is usually recorded with a suffix (.Local/Google/Other). The base version is
-    recorded only on Android, as well as for the old NTP (&quot;NTP4&quot;) on
-    other platforms.
+    is usually recorded with a suffix (.Local*/Google/Other). The base version
+    is recorded only on Android, as well as for the old NTP (&quot;NTP4&quot;)
+    on other platforms. Recorded only once per tab, i.e. excluding back/forward
+    navigations.
   </summary>
 </histogram>
 
@@ -75497,6 +75830,22 @@
   </summary>
 </histogram>
 
+<histogram name="Thumbnails.CopyFromSurfaceTime" units="ms">
+  <owner>treib@chromium.org</owner>
+  <summary>
+    While taking a screenshot of the current tab for use as a thumbnail on the
+    New Tab page, the time it took to copy the tab's contents into a bitmap.
+  </summary>
+</histogram>
+
+<histogram name="Thumbnails.ProcessBitmapTime" units="ms">
+  <owner>treib@chromium.org</owner>
+  <summary>
+    While taking a screenshot of the current tab for use as a thumbnail on the
+    New Tab page, the time it took to post-process the captured bitmap.
+  </summary>
+</histogram>
+
 <histogram name="TileManager.ExceededMemoryBudget" enum="TileMemoryBudget">
   <owner>reveman@chromium.org</owner>
   <owner>vmpstr@chromium.org</owner>
@@ -75579,6 +75928,16 @@
   </summary>
 </histogram>
 
+<histogram name="Toolbar.ShowToolsMenuResponsiveness" units="ms">
+  <owner>peterlaurens@chromium.org</owner>
+  <summary>
+    Number of milliseconds passed between the event that triggers the
+    presentation of the tools menu (the main menu of actions accessed from the
+    toolbar), and the actual appearance of the menu on screen. Includes the
+    animation duration.
+  </summary>
+</histogram>
+
 <histogram name="TopSites.NumberOfApplyBlacklist">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>The number of times TopSitesImpl::ApplyBlacklist is called.</summary>
@@ -75896,6 +76255,26 @@
   </summary>
 </histogram>
 
+<histogram name="Translate.CompactInfobar.TranslationsPerPage"
+    units="translations">
+  <owner>ramyasharma@google.com</owner>
+  <summary>
+    Records the number of times a page is translated, every time the page is
+    translated. For instance on a page a) translation from A to B, we record
+    &quot;1&quot; b) from A to B - we record &quot;1&quot; and revert from B to
+    A - we record &quot;2&quot; c) from A to B - we record &quot;1&quot;, then
+    translation to C - we record &quot;2&quot;. d) from A to B - we record
+    &quot;1&quot;, then translation to C - we record &quot;2&quot; and then
+    revert to A - we record &quot;3&quot;. We increment the translation count:
+    a) every time the target language is changed. b) every time we revert to the
+    original language (user can only revert to original language and not
+    intermediate target languages). This essentially means 1 denotes &gt;= 1
+    translations, 2 is &gt;=2 translations per page and so on. This will give us
+    a sense of how often people try out several translates on a page, or flip
+    back and forth.
+  </summary>
+</histogram>
+
 <histogram name="Translate.ContentLanguage" enum="TranslateLanguage">
   <owner>kenjibaheux@google.com</owner>
   <summary>
@@ -76088,14 +76467,23 @@
 <histogram name="Translate.Ranker.Timer.DownloadModel" units="ms">
   <owner>rogerm@google.com</owner>
   <summary>
-    Time taken for the TranslateRanker to download its model, in ms.
+    Time taken for the Translate Ranker Model Loader to download its model from
+    the configured URL, in ms.
   </summary>
 </histogram>
 
 <histogram name="Translate.Ranker.Timer.ParseModel" units="ms">
   <owner>rogerm@google.com</owner>
   <summary>
-    Time taken for the TranslateRanker to parse its model, in ms.
+    Time taken for the Translate Ranker Model Loader to parse its model, in ms.
+  </summary>
+</histogram>
+
+<histogram name="Translate.Ranker.Timer.ReadModel" units="ms">
+  <owner>rogerm@google.com</owner>
+  <summary>
+    Time taken for the Translate Ranker Model Loader to read its model from
+    local storage (cache), in ms.
   </summary>
 </histogram>
 
@@ -76109,6 +76497,14 @@
   </summary>
 </histogram>
 
+<histogram name="Translate.Ranker.Timer.WriteModel" units="ms">
+  <owner>rogerm@google.com</owner>
+  <summary>
+    Time taken for the Translate Ranker Model Loader to write its model to local
+    storage, in ms.
+  </summary>
+</histogram>
+
 <histogram name="Translate.ReportLanguageDetectionError">
   <owner>kenjibaheux@google.com</owner>
   <summary>
@@ -81654,6 +82050,31 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.BWE.MidCallProbing.Initiated" units="kbps">
+  <owner>philipel@chromium.org</owner>
+  <summary>
+    The bitrate that will be probed, triggered by an update to the max
+    configured bitrate.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.BWE.MidCallProbing.ProbedKbps" units="kbps">
+  <owner>philipel@chromium.org</owner>
+  <summary>
+    The resulting bitrate probed, triggered by an update to the max configured
+    bitrate.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.BWE.MidCallProbing.Success" units="kbps">
+  <owner>philipel@chromium.org</owner>
+  <summary>
+    A successful probing attempt for a given bitrate, triggered by an update to
+    the max configured bitrate. NOTE! This is not the resulting bitrate from
+    a probing attempt, see WebRTC.BWE.MidCallProbing.ProbedKbps.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.BWE.RampUpTimeTo1000kbpsInMs" units="ms">
   <owner>holmer@chromium.org</owner>
   <summary>
@@ -82126,6 +82547,35 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.Video.BadCall.Any" units="%">
+  <owner>sprang@chromium.org</owner>
+  <summary>
+    Fraction of time the call was classified as bad because of any reason.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.Video.BadCall.FrameRate" units="%">
+  <owner>sprang@chromium.org</owner>
+  <summary>
+    Fraction of time the call was classified as bad because of low framerate.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.Video.BadCall.FrameRateVariance" units="%">
+  <owner>sprang@chromium.org</owner>
+  <summary>
+    Fraction of time the call was classified as bad because of high framerate
+    variance.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.Video.BadCall.Qp" units="%">
+  <owner>sprang@chromium.org</owner>
+  <summary>
+    Fraction of time the call was classified as bad because of high qp.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.Video.BandwidthLimitedResolutionInPercent" units="%">
   <owner>asapersson@chromium.org</owner>
   <summary>
@@ -83849,7 +84299,7 @@
 
 <histogram_suffixes_list>
 
-<histogram_suffixes name="AccountInvestigationReportingType">
+<histogram_suffixes name="AccountInvestigationReportingType" separator="_">
   <suffix name="OnChange"
       label="Driven from a change in signin status or change in content area
              GAIA accounts."/>
@@ -83862,7 +84312,7 @@
   <affected-histogram name="Signin.IsShared"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ActiveNetworkState">
+<histogram_suffixes name="ActiveNetworkState" separator="_">
   <suffix name="Offline"
       label="network manager thinks that the active network is offline"/>
   <suffix name="Online"
@@ -83892,7 +84342,7 @@
       name="PasswordManager.AffiliationDummyData.RequestSuccess"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AlternateProtocol">
+<histogram_suffixes name="AlternateProtocol" separator="_">
   <suffix name="AlternateProtocol_spdy"
       label="with alternate protocol available but http is used"/>
   <suffix name="AlternateProtocol_http"
@@ -83923,7 +84373,7 @@
   <affected-histogram name="Arc.boot_progress"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AndroidCrashUploadTypes">
+<histogram_suffixes name="AndroidCrashUploadTypes" separator="_">
   <suffix name="Browser" label="Measures browser crash uploads."/>
   <suffix name="GPU" label="Measures GPU crash uploads."/>
   <suffix name="Other" label="Measures other crash uploads."/>
@@ -83959,7 +84409,7 @@
   <affected-histogram name="Bluetooth.Web.Android"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AndroidGetAccountsTypes">
+<histogram_suffixes name="AndroidGetAccountsTypes" separator="_">
   <suffix name="AccountManager" label="Using Android AccountManager API"/>
   <suffix name="GoogleAuthUtil" label="Using GoogleAuthUtil API"/>
   <affected-histogram name="Signin.AndroidGetAccountsTime"/>
@@ -83993,14 +84443,14 @@
   <affected-histogram name="Startup.AppListFirstPaintWarmStart"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AsyncDNSPref">
+<histogram_suffixes name="AsyncDNSPref" separator="_">
   <suffix name="Disabled"/>
   <suffix name="Enabled"/>
   <affected-histogram name="AsyncDNS.PrefDefaultSource"/>
   <affected-histogram name="AsyncDNS.PrefSource"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AsyncSlowStart">
+<histogram_suffixes name="AsyncSlowStart" separator="_">
   <suffix name="AsyncSlowStart" label="Async Slow Start on"/>
   <suffix name="AsyncSlowStart_off" label="Async Slow Start off"/>
   <suffix name="AsyncSlowStart_on" label="Async Slow Start on"/>
@@ -84008,7 +84458,7 @@
   <affected-histogram name="Renderer4.StartToFinish"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AttemptResultCode">
+<histogram_suffixes name="AttemptResultCode" separator="_">
   <obsolete>
     Deprecated 2016/03. The async set-as-default experiments are finished.
   </obsolete>
@@ -84088,7 +84538,7 @@
   <affected-histogram name="Autofill.SaveCreditCardPrompt.Upload"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="AutofillServerExperiments">
+<histogram_suffixes name="AutofillServerExperiments" separator="_">
   <obsolete>
     Deprecated as of at least 2013. Current autofill experiments rely on Finch
     rather than a custom experimentation setup.
@@ -84279,7 +84729,7 @@
   <affected-histogram name="Blink.Canvas.ToDataURL"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="BlinkGCReason">
+<histogram_suffixes name="BlinkGCReason" separator="_">
   <suffix name="IdleGC" label="Idle GC"/>
   <suffix name="PreciseGC" label="Precise GC"/>
   <suffix name="ConservativeGC" label="Conservative GC"/>
@@ -84291,6 +84741,8 @@
 
 <histogram_suffixes name="BrowserMemoryAllocator2" separator=".">
   <suffix name="Resident" label="Only counting resident memory."/>
+  <suffix name="PrivateMemoryFootprint"
+      label="Only counting private resident + swapped/compressed memory."/>
   <suffix name="Malloc" label="Constrained to malloc allocator."/>
   <affected-histogram name="Memory.Experimental.Browser2"/>
 </histogram_suffixes>
@@ -84417,7 +84869,7 @@
   <affected-histogram name="SimpleCache.WriteResult2"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CacheListSize">
+<histogram_suffixes name="CacheListSize" separator="_">
   <obsolete>
     Experiments no longer active.
   </obsolete>
@@ -84441,7 +84893,7 @@
   <affected-histogram name="PLT.BeginToFinish_Reload"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CacheSensitivityAnalysis">
+<histogram_suffixes name="CacheSensitivityAnalysis" separator="_">
   <obsolete>
     Experiments no longer active.
   </obsolete>
@@ -84467,7 +84919,7 @@
   <affected-histogram name="PLT.CommitToFirstPaint_CacheSensitivity"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CacheSensitivityHistograms">
+<histogram_suffixes name="CacheSensitivityHistograms" separator="_">
   <suffix name="CacheSensitivity" label="Cache Sensivitiy Analysis"/>
   <affected-histogram name="PLT.BeginToFinish"/>
   <affected-histogram name="PLT.BeginToFinishDoc"/>
@@ -84475,7 +84927,7 @@
   <affected-histogram name="PLT.CommitToFirstPaint"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CacheSensitivityHistograms">
+<histogram_suffixes name="CacheSensitivityHistograms" separator="_">
   <suffix name="CacheSensitivity" label="Cache Sensivitiy Analysis"/>
   <affected-histogram name="PLT.BeginToFinish"/>
   <affected-histogram name="PLT.BeginToFinishDoc"/>
@@ -84483,7 +84935,7 @@
   <affected-histogram name="PLT.CommitToFirstPaint"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CacheThrottle">
+<histogram_suffixes name="CacheThrottle" separator="_">
   <suffix name="CacheThrottle_On" label="Throttling payload requests."/>
   <suffix name="CacheThrottle_Off" label="Control group."/>
   <affected-histogram name="DiskCache.TotalIOTime"/>
@@ -84498,7 +84950,7 @@
   <affected-histogram name="PLT.BeginToFinish_Reload"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CanvasRequestedImageMimeTypeFunctions">
+<histogram_suffixes name="CanvasRequestedImageMimeTypeFunctions" separator="_">
   <suffix name="toDataURL" label="Image formats passed to canvas.toDataURL"/>
   <suffix name="toBlobCallback"
       label="Image formats passed to canvas.toBlob (callback)"/>
@@ -84600,7 +85052,7 @@
   <affected-histogram name="MobileStartup.ToolbarInflationTime"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ChromeOS.MachineIdRegen.AgeSeconds">
+<histogram_suffixes name="ChromeOS.MachineIdRegen.AgeSeconds" separator="_">
   <suffix name="Network"/>
   <suffix name="Periodic"/>
   <suffix name="Unknown"/>
@@ -84746,7 +85198,7 @@
       name="Scheduling.Renderer.BeginMainFrameStartToCommitDuration"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ConnCountImpact">
+<histogram_suffixes name="ConnCountImpact" separator="_">
   <suffix name="conn_count_16" label="with 16 persistent connections per host"/>
   <suffix name="conn_count_4" label="with 4 persistent connections per host"/>
   <suffix name="conn_count_5" label="with 5 persistent connections per host"/>
@@ -84784,7 +85236,7 @@
   <affected-histogram name="ConnectivityDiagnostics.TimeTaken"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ConnnectBackupJobs">
+<histogram_suffixes name="ConnnectBackupJobs" separator="_">
   <suffix name="ConnectBackupJobsEnabled"/>
   <suffix name="ConnectBackupJobsDisabled"/>
   <affected-histogram name="Net.PreconnectUtilization"/>
@@ -84924,7 +85376,7 @@
   <affected-histogram name="Search.ContextualSearchQuickActions.ResultsSeen"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CreditCardScanSuccess">
+<histogram_suffixes name="CreditCardScanSuccess" separator="_">
   <suffix name="Completed" label="Credit card scan completed."/>
   <suffix name="Cancelled" label="Credit card scan was cancelled."/>
   <affected-histogram name="Autofill.ScanCreditCard.Duration"/>
@@ -84937,7 +85389,7 @@
   <affected-histogram name="CrosFirstRun.TimeSpentOnStep"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="CurrentTabState">
+<histogram_suffixes name="CurrentTabState" separator="_">
   <suffix name="Initial" label="For a tab that is just being created."/>
   <suffix name="Active"
       label="For an active tab which is shown foreground in a browser window."/>
@@ -84950,7 +85402,7 @@
   <affected-histogram name="Tabs.StateTransfer.Time"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DataReductionProxy">
+<histogram_suffixes name="DataReductionProxy" separator="_">
   <obsolete>
     Deprecated 9/2016.
   </obsolete>
@@ -85002,7 +85454,7 @@
   <affected-histogram name="DataReductionProxy.LoFi.Accuracy"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DataReductionProxy.MimeType">
+<histogram_suffixes name="DataReductionProxy.MimeType" separator="_">
   <suffix name="Application" label="Application mime-type"/>
   <suffix name="Unknown"
       label="Deprecated. Moved to UnknownMime in M46. Unknown mime-type"/>
@@ -85432,7 +85884,7 @@
   <affected-histogram name="DataUse.BackgroundToFirstDownstream"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DefaultAppsExperiment">
+<histogram_suffixes name="DefaultAppsExperiment" separator="_">
   <suffix name="NoDefaultApps" label="User's without default apps installed"/>
   <suffix name="WithDefaultApps" label="User's with default apps installed"/>
   <affected-histogram name="Extensions.AppTabLaunchType"/>
@@ -85445,7 +85897,7 @@
   <affected-histogram name="Profile.AppCount"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DefaultPinnedApps">
+<histogram_suffixes name="DefaultPinnedApps" separator="_">
   <obsolete>
     Deprecated as of 12/2013. Default pinned apps trial is finished.
   </obsolete>
@@ -85455,7 +85907,8 @@
   <affected-histogram name="Cros.ClickOnShelf"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DeprecatedPrerenderSource" ordering="prefix">
+<histogram_suffixes name="DeprecatedPrerenderSource" separator="_"
+    ordering="prefix">
   <obsolete>
     Deprecated August 2016
   </obsolete>
@@ -85762,7 +86215,8 @@
   <affected-histogram name="Platform.DiskUsage.LeastUsedAccountDays"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DNS.HostCache.UpdateStale.AddressListDeltaType">
+<histogram_suffixes name="DNS.HostCache.UpdateStale.AddressListDeltaType"
+    separator="_">
   <suffix name="Identical" label="Same addresses, in the same order."/>
   <suffix name="Reordered" label="Same addresses, in a different order."/>
   <suffix name="Overlap" label="Some same addreses, some different."/>
@@ -85771,7 +86225,7 @@
   <affected-histogram name="DNS.HostCache.UpdateStale.NetworkChanges"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="DnsImpact2">
+<histogram_suffixes name="DnsImpact2" separator="_">
   <suffix name="disabled_prefetch"
       label="DNS pre-resolving is disabled in these clients"/>
   <suffix name="disabled_prefetch_4_connections"
@@ -85806,7 +86260,7 @@
   </affected-histogram>
 </histogram_suffixes>
 
-<histogram_suffixes name="DnsImpact3">
+<histogram_suffixes name="DnsImpact3" separator="_">
   <suffix name="disabled_prefetch" label="with DNS pre-resolving disabled"/>
   <suffix name="parallel_4_prefetch"
       label="with only 4 concurrent speculative resolutions done in parallel"/>
@@ -85831,7 +86285,7 @@
   </affected-histogram>
 </histogram_suffixes>
 
-<histogram_suffixes name="DnsParallelism">
+<histogram_suffixes name="DnsParallelism" separator="_">
   <suffix name="parallel_10"
       label="with only 10 concurrent resolutions done in parallel"/>
   <suffix name="parallel_14"
@@ -85929,7 +86383,7 @@
   <affected-histogram name="Media.EME.Widevine.TimeTo"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="EngagementScoreBuckets">
+<histogram_suffixes name="EngagementScoreBuckets" separator="_">
   <owner>calamity@chromium.org</owner>
   <suffix name="0"/>
   <suffix name="10"/>
@@ -86132,7 +86586,7 @@
   <affected-histogram name="FileBrowser.Load"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="FirstPacketSplit">
+<histogram_suffixes name="FirstPacketSplit" separator="_">
   <suffix name="first_packet_intact"
       label="with GET/POST headers often using only 1 packet"/>
   <suffix name="first_packet_split"
@@ -86169,7 +86623,7 @@
   <affected-histogram name="Notifications.Freedesktop.Capabilities"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="FromGWS">
+<histogram_suffixes name="FromGWS" separator="_">
   <suffix name="FromGWS"
       label="Only page loads that are a result of a navigation from a web
              search are considered."/>
@@ -86200,7 +86654,7 @@
   <affected-histogram name="Geolocation.SettingsDialog.SuppressEvent"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Gesture">
+<histogram_suffixes name="Gesture" separator="_">
   <suffix name="Wheel"
       label="Measure the size of scroller that users wheel scroll"/>
   <suffix name="Touch"
@@ -86208,13 +86662,13 @@
   <affected-histogram name="Event.Scroll.ScrollerSize.OnScroll"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="GLApisWithErrorReporting">
+<histogram_suffixes name="GLApisWithErrorReporting" separator="_">
   <suffix name="TexImage2D" label="All GL APIs that allocate a 2D texture."/>
   <suffix name="TexImage3D" label="All GL APIs that allocate a 3D texture."/>
   <affected-histogram name="GPU.Error"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="GlobalSdch">
+<histogram_suffixes name="GlobalSdch" separator="_">
   <suffix name="global_disable_sdch" label="with SDCH completely disabled"/>
   <suffix name="global_enable_sdch"
       label="with SDCH support for applicable sites"/>
@@ -86249,7 +86703,7 @@
   <affected-histogram name="Renderer4.StartToFinish"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="GoogleSearchVariations">
+<histogram_suffixes name="GoogleSearchVariations" separator="_">
   <owner>kmadhusu@chromium.org</owner>
   <suffix name="_PrerenderDisabled"
       label="Counts number of Google searches from various access points in
@@ -86280,11 +86734,13 @@
 
 <histogram_suffixes name="GpuMemoryAllocator2" separator=".">
   <suffix name="Resident" label="Only counting resident memory."/>
+  <suffix name="PrivateMemoryFootprint"
+      label="Only counting private resident + swapped/compressed memory."/>
   <suffix name="Malloc" label="Constrained to malloc allocator."/>
   <affected-histogram name="Memory.Experimental.Gpu2"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="GWSChromeJointExperiment">
+<histogram_suffixes name="GWSChromeJointExperiment" separator="_">
   <suffix name="Experiment1"
       label="Only page loads that are a result of a navigation from a web
              search under a specific web search/Chrome joint experiment.
@@ -86477,7 +86933,7 @@
   <affected-histogram name="Net.HttpJob.PrefilterBytesRead"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="HttpPipeliningCompatibility">
+<histogram_suffixes name="HttpPipeliningCompatibility" separator="_">
   <suffix name="disable_test" label="Do nothing"/>
   <suffix name="enable_test" label="Test connection for HTTP pipelining"/>
   <affected-histogram name="NetConnectivity.Pipeline.0.NetworkError"/>
@@ -86504,7 +86960,7 @@
   <affected-histogram name="NetConnectivity.Pipeline.Success"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="IdleSktToImpact">
+<histogram_suffixes name="IdleSktToImpact" separator="_">
   <suffix name="idle_timeout_5"
       label="with 5-second unused idle socket timeout"/>
   <suffix name="idle_timeout_10"
@@ -86619,13 +87075,13 @@
   <affected-histogram name="Installer.TotalMBsDownloadedFrom"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Instant">
+<histogram_suffixes name="Instant" separator="_">
   <suffix name="Extended" label="Suggestions + Results"/>
   <suffix name="Instant" label="Results"/>
   <affected-histogram name="Instant.SessionsStorageNamespace"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="InstantExtended_QuerytoQuery">
+<histogram_suffixes name="InstantExtended_QuerytoQuery" separator="_">
   <obsolete>
     All relevant histograms have been marked as obsolete as of Sep 2016.
   </obsolete>
@@ -86640,7 +87096,7 @@
   <affected-histogram name="InstantExtended.PercentageMatchV2_URLtoURL"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="InstantSearchClicks">
+<histogram_suffixes name="InstantSearchClicks" separator="_">
   <obsolete>
     Deprecated as of 7/2015.
   </obsolete>
@@ -86689,7 +87145,7 @@
   <affected-histogram name="Startup.FirstCommitNavigationTime2"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="InterProcessTimeTicksConversionType">
+<histogram_suffixes name="InterProcessTimeTicksConversionType" separator="_">
   <owner>ppi@chromium.org</owner>
   <suffix name="BrowserToRenderer"/>
   <suffix name="RendererToBrowser"/>
@@ -86751,7 +87207,7 @@
   <affected-histogram name="WebRTC.SystemSendPacketDuration"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="IPv6_Probe">
+<histogram_suffixes name="IPv6_Probe" separator="_">
   <suffix name="IPv6_probe_skipped"
       label="with IPv6 not probed, and default OS settings used"/>
   <suffix name="IPv6_probe_done"
@@ -86794,7 +87250,7 @@
   <affected-histogram name="JSDialogs.CharacterCount"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="LateBindingExperiment">
+<histogram_suffixes name="LateBindingExperiment" separator="_">
   <suffix name="disable_late_binding" label="socket late binding is disabled"/>
   <suffix name="enable_late_binding" label="socket late binding is enabled"/>
   <affected-histogram name="Net.SocketIdleTimeBeforeNextUse_ReusedSocket"/>
@@ -86845,6 +87301,7 @@
   <affected-histogram name="LevelDBEnv.IDB.IOError.BFE"/>
   <affected-histogram name="LevelDBEnv.IOError.BFE"/>
   <affected-histogram name="LevelDBEnv.ServiceWorker.IOError.BFE"/>
+  <affected-histogram name="MojoLevelDBEnv.IOError.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBOpenErrors.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBReadErrors.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBWriteErrors.BFE"/>
@@ -86930,7 +87387,7 @@
   <affected-histogram name="LevelDBEnv.TimeUntilSuccessFor"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="LevelDBOpenResults">
+<histogram_suffixes name="LevelDBOpenResults" separator="_">
   <suffix name="DomDistillerStore" label="Databases for DomDistillerStore"/>
   <suffix name="GCMKeyStore" label="Databases for GCMKeyStore"/>
   <suffix name="ImageManager" label="Databases for ImageManager"/>
@@ -86998,7 +87455,7 @@
   <affected-histogram name="Renderer4.LockExistingCachedImage"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="LowMemoryMargin">
+<histogram_suffixes name="LowMemoryMargin" separator="_">
   <suffix name="default" label="Low memory margin set to the system default"/>
   <suffix name="off" label="Low memory notification disabled"/>
   <suffix name="0mb" label="Low memory margin set to 0MB"/>
@@ -87016,6 +87473,12 @@
   <affected-histogram name="Tabs.SadTab.KillCreated"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="MacAudioInputVariants" separator="_">
+  <suffix name="HighLatency"
+      label="Measures the standard Mac audio driver (i.e. not low-latency)."/>
+  <affected-histogram name="Media.Audio.InputStartupSuccessMac"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="ManifestProperties" separator=".">
   <suffix name="name"/>
   <suffix name="short_name"/>
@@ -87249,6 +87712,14 @@
   <affected-histogram name="Memory.Coordinator.TotalPrivate"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="Mobile.DefaultBrowser.SystemDefaultBrowser.Type"
+    separator=".">
+  <suffix name="ChromeSystem" label="Chrome is a system installed browser."/>
+  <suffix name="ChromeNotSystem"
+      label="Chrome is not a system installed browser."/>
+  <affected-histogram name="Mobile.DefaultBrowser.SystemBrowserCount"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="Mobile.DefaultBrowser.Type" separator=".">
   <suffix name="ChromeDefault" label="Chrome is the default browser."/>
   <suffix name="NoDefault" label="There is no default browser."/>
@@ -87345,7 +87816,7 @@
   <affected-histogram name="WebRTC.Stun.SuccessPercent"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NavigationCharacteristic">
+<histogram_suffixes name="NavigationCharacteristic" separator="_">
   <suffix name="ExistingRenderer_BeforeUnloadDiscounted"
       label="Navigation reused an existing renderer process. Time spent in
              beforeunload subtracted."/>
@@ -87369,7 +87840,7 @@
   <affected-histogram name="Navigation.TimeToURLJobStart"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NavigationPreloadEnabled">
+<histogram_suffixes name="NavigationPreloadEnabled" separator="_">
   <affected-histogram
       name="ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time"/>
   <affected-histogram
@@ -87379,7 +87850,7 @@
       name="ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NavigationPreloadOrWorkerFirst">
+<histogram_suffixes name="NavigationPreloadOrWorkerFirst" separator="_">
   <suffix name="SWStartFirst"
       label="The service worker finished preparing before the navigation
              preload response arrived."/>
@@ -88697,7 +89168,7 @@
   <affected-histogram name="Net.HttpProxy.ConnectLatency.Secure"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NetProxyResolverExecutionTime">
+<histogram_suffixes name="NetProxyResolverExecutionTime" separator="_">
   <suffix name="UrlOver2K" label="URL length was over 2K"/>
   <suffix name="UrlOver4K" label="URL length was over 4K"/>
   <suffix name="UrlOver8K" label="URL length was over 8K"/>
@@ -88768,6 +89239,7 @@
   <suffix name="client" label="Suggestions coming from the client."/>
   <suffix name="server" label="Suggestions coming from the server."/>
   <suffix name="popular" label="Non-personalized, popular suggestions."/>
+  <suffix name="homepage" label="The currently set home page."/>
   <suffix name="whitelist"
       label="Installed whitelist entry point suggestions."/>
   <suffix name="client0">
@@ -88817,7 +89289,7 @@
   <affected-histogram name="NewTabPage.TilesReceivedTime"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NextTabState">
+<histogram_suffixes name="NextTabState" separator="_">
   <suffix name="Active"
       label="For a tab active which is shown foreground in a browser window."/>
   <suffix name="Inactive"
@@ -88831,7 +89303,7 @@
   <affected-histogram name="Tabs.StateTransfer.Time_Inactive"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NotificationDisplayExperiment">
+<histogram_suffixes name="NotificationDisplayExperiment" separator="_">
   <suffix name="Fullscreen.Shown"
       label="A notification sent by a fullscreen app or webpage that is
              displayed."/>
@@ -89257,7 +89729,7 @@
   <affected-histogram name="UMA.Histograms.Activity"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="OverlappedReadImpact">
+<histogram_suffixes name="OverlappedReadImpact" separator="_">
   <obsolete>
     Experiments no longer active.
   </obsolete>
@@ -89415,6 +89887,14 @@
   <affected-histogram name="PageLoad.PageTiming.ForegroundDuration"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsAtTimingCallbackDispatch"
+    separator=".">
+  <suffix name="AtTimingCallbackDispatch"
+      label="Evaluated at the time timing update calls are dispatched to
+             observers."/>
+  <affected-histogram name="PageLoad.Internal.PageLoadTimingStatus"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsCacheInfo" separator=".">
   <suffix name="NoStore" label="Main resource had cache-control: no-store"/>
   <affected-histogram
@@ -89425,6 +89905,28 @@
       name="PageLoad.ParseTiming.NavigationToParseStart.LoadType.ForwardBackNavigation"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsClientsAmp" separator="."
+    ordering="prefix">
+  <suffix name="Clients.AMP"
+      label="AMP page load. Same page navigations are not tracked."/>
+  <suffix name="Clients.AMP.AmpCache"
+      label="AMP page load from the AMP cache CDN."/>
+  <suffix name="Clients.AMP.GoogleSearch"
+      label="AMP page load in the Google Search AMP viewer. Same page
+             navigations are not tracked."/>
+  <suffix name="Clients.AMP.GoogleNews"
+      label="AMP page load in the Google News AMP viewer. Same page
+             navigations are not tracked."/>
+  <affected-histogram
+      name="PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired"/>
+  <affected-histogram name="PageLoad.DocumentTiming.NavigationToFirstLayout"/>
+  <affected-histogram
+      name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/>
+  <affected-histogram
+      name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/>
+  <affected-histogram name="PageLoad.ParseTiming.NavigationToParseStart"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsClientsAmpCachePages" separator="."
     ordering="prefix">
   <obsolete>
@@ -89445,6 +89947,9 @@
 
 <histogram_suffixes name="PageLoadMetricsClientsAmpCachePages2" separator="."
     ordering="prefix">
+  <obsolete>
+    Deprecated in favor of PageLoad.Clients.AMP.*.
+  </obsolete>
   <suffix name="Clients.AMPCache2"
       label="PageLoadMetrics that are a result of a navigations to an AMP
              cache page. Same page navigations are not tracked."/>
@@ -89958,7 +90463,7 @@
       name="PageLoad.Experimental.AbortTiming.Reload.BeforeCommit"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PageLoadType">
+<histogram_suffixes name="PageLoadType" separator="_">
   <suffix name="HistoryLoad"
       label="but only for user pressing back or forward"/>
   <suffix name="LinkLoad"
@@ -89994,7 +90499,7 @@
   <affected-histogram name="Renderer4.BeginToFinishDoc"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PageLoadType">
+<histogram_suffixes name="PageLoadType" separator="_">
   <suffix name="HistoryLoad"
       label="but only for user pressing back or forward"/>
   <suffix name="LinkLoad"
@@ -90083,7 +90588,7 @@
   <affected-histogram name="PasswordManager.TotalAccounts"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PasswordManagerMonitor">
+<histogram_suffixes name="PasswordManagerMonitor" separator="_">
   <obsolete>
     Deprecated as of 03/2016.
   </obsolete>
@@ -90116,6 +90621,15 @@
   <affected-histogram name="PasswordManager.SavePasswordPromptResponse"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PasswordProtectionTrigger" separator=".">
+  <suffix name="PasswordFieldOnFocus"
+      label="Password protection triggered by password field on focus event."/>
+  <suffix name="ProtectedPasswordEntry"
+      label="Password protection triggered by password reuse event."/>
+  <affected-histogram name="PasswordProtection.RequestOutcome"/>
+  <affected-histogram name="PasswordProtection.Verdict"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PasswordReuseSourceRealm" separator=".">
   <suffix name="FromHttpRealm"
       label="The account in question was saved on an HTTP site."/>
@@ -90391,7 +90905,7 @@
   <affected-histogram name="NaCl.Perf.Size.PNaClTranslatedNexe"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PositionVariants">
+<histogram_suffixes name="PositionVariants" separator="_">
   <suffix name="0_0" label="Only snippets on position 0"/>
   <suffix name="1_2" label="Only snippets on position 1-2"/>
   <suffix name="3_4" label="Only snippets on position 3-4"/>
@@ -90406,7 +90920,7 @@
   <affected-histogram name="NewTabPage.Snippets.CardShownScoreNew"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PpapiPluginName">
+<histogram_suffixes name="PpapiPluginName" separator="_">
   <suffix name="libpepflashplayer.so" label="Flash player on Linux or Cros"/>
   <suffix name="libwidevinecdmadapter.so"
       label="Widevine CDM on Linux or Cros"/>
@@ -90438,7 +90952,7 @@
   <affected-histogram name="Settings.JsonDataWriteCount"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Prefetch">
+<histogram_suffixes name="Prefetch" separator="_">
   <suffix name="ContentPrefetchPrefetchOff"
       label="Prefetch is completely disabled."/>
   <suffix name="ContentPrefetchPrefetchOn"
@@ -90456,7 +90970,7 @@
   <affected-histogram name="PLT.PerceivedLoadTime_PrerenderLoad"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Prerender">
+<histogram_suffixes name="Prerender" separator="_">
   <obsolete>
     Deprecated August 2016
   </obsolete>
@@ -90508,7 +91022,7 @@
   <affected-histogram name="Prerender.SimulatedLocalBrowsingPLT"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PrerenderHoverType" ordering="prefix">
+<histogram_suffixes name="PrerenderHoverType" separator="_" ordering="prefix">
   <obsolete>
     deprecated May 10 2012
   </obsolete>
@@ -90532,7 +91046,7 @@
   <affected-histogram name="Prerender.TimeToClick"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PrerenderModeType">
+<histogram_suffixes name="PrerenderModeType" separator="_">
   <obsolete>
     Deprecated August 2016
   </obsolete>
@@ -90577,7 +91091,7 @@
   <affected-histogram name="Prerender.PrefetchTTFCP.Warm.NoStore"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="PrerenderSource" ordering="prefix">
+<histogram_suffixes name="PrerenderSource" separator="_" ordering="prefix">
   <suffix name="" label="All prerenders."/>
   <suffix name="gws" label="GWS triggered prerender."/>
   <suffix name="externalrequest" label="Externally triggered prerender."/>
@@ -90719,7 +91233,7 @@
   <affected-histogram name="UserImage.ProfileDownloadTime"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ProgressiveScan">
+<histogram_suffixes name="ProgressiveScan" separator="_">
   <suffix name="FullScan" label="Using WPA_supplicant to scan."/>
   <suffix name="33Percent_4MinMax"
       label="Progressive scan @ 33%, 4 frequency bins."/>
@@ -90761,7 +91275,7 @@
   <affected-histogram name="Protector.StartupSettings"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ProxyConnectionImpact">
+<histogram_suffixes name="ProxyConnectionImpact" separator="_">
   <suffix name="proxy_connections_16"
       label="with 16 connections per proxy server"/>
   <suffix name="proxy_connections_32"
@@ -91057,6 +91571,8 @@
 
 <histogram_suffixes name="RendererMemoryAllocator2" separator=".">
   <suffix name="Resident" label="Only counting resident memory."/>
+  <suffix name="PrivateMemoryFootprint"
+      label="Only counting private resident + swapped/compressed memory."/>
   <suffix name="Malloc" label="Constrained to malloc allocator."/>
   <suffix name="PartitionAlloc" label="Constrained to partition allocator."/>
   <suffix name="BlinkGC" label="Constrained to blink GC allocator."/>
@@ -91090,7 +91606,7 @@
   <affected-histogram name="Media.EME.RequestMediaKeySystemAccess"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="RequestThrottlerTypes">
+<histogram_suffixes name="RequestThrottlerTypes" separator="_">
   <suffix name="SuggestionFetcher"
       label="Fetcher for content suggestions on mobile NTP">
     <obsolete>
@@ -91139,7 +91655,8 @@
   <affected-histogram name="ResourcePrefetchPredictor.NetworkType"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ResourcePrefetchPredictorPLTNetworkTypes">
+<histogram_suffixes name="ResourcePrefetchPredictorPLTNetworkTypes"
+    separator="_">
   <obsolete>
     Deprecated September 2016. No longer recorded.
   </obsolete>
@@ -91181,7 +91698,8 @@
   <affected-histogram name="ResourcePrefetchPredictor.PLT.Prefetched"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ResourcePrefetchPredictorPredictedStatsVariedMax">
+<histogram_suffixes name="ResourcePrefetchPredictorPredictedStatsVariedMax"
+    separator="_">
   <obsolete>
     Deprecated September 2016. No longer recorded.
   </obsolete>
@@ -91225,7 +91743,8 @@
       name="ResourcePrefetchPredictor.Url.PredictedPrefetchMisses_PercentOfTotalPrefetched"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ResourcePrefetchPredictorPredictedStatTypes">
+<histogram_suffixes name="ResourcePrefetchPredictorPredictedStatTypes"
+    separator="_">
   <obsolete>
     Deprecated September 2016. No longer recorded.
   </obsolete>
@@ -91247,7 +91766,7 @@
       name="ResourcePrefetchPredictor.Url.PredictedPrefetchMisses"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ResourceSchedulerClientBreakDown">
+<histogram_suffixes name="ResourceSchedulerClientBreakDown" separator="_">
   <obsolete>
     Deprecated 1/2016
   </obsolete>
@@ -91457,7 +91976,7 @@
   <affected-histogram name="SB2.ResourceTypes2"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SBInterstitial">
+<histogram_suffixes name="SBInterstitial" separator="_">
   <obsolete>
     deprecated November 10 2012 crrev.com/167056
   </obsolete>
@@ -91490,7 +92009,7 @@
   <affected-histogram name="WebRTC.Video.Screenshare.Layer1"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ScrollUpdateHandledThread">
+<histogram_suffixes name="ScrollUpdateHandledThread" separator="_">
   <suffix name="Main" label="ScrollUpdate handled on main thread"/>
   <suffix name="Impl" label="ScrollUpdate handled on impl thread"/>
   <affected-histogram
@@ -91607,7 +92126,7 @@
   <affected-histogram name="ServiceWorker.ContextRequestHandlerStatus"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.EventType">
+<histogram_suffixes name="ServiceWorker.EventType" separator="_">
   <suffix name="ACTIVATE" label="ACTIVATE"/>
   <suffix name="INSTALL" label="INSTALL"/>
   <suffix name="SYNC" label="SYNC"/>
@@ -91651,7 +92170,7 @@
   <affected-histogram name="ServiceWorker.StartWorker.Time_NewProcess"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.FailureStreak">
+<histogram_suffixes name="ServiceWorker.FailureStreak" separator="_">
   <suffix name="1" label="Failed one time."/>
   <suffix name="2" label="Failed two times."/>
   <suffix name="3" label="Failed three times."/>
@@ -91668,7 +92187,7 @@
   <affected-histogram name="ServiceWorker.NavigationHintPrecision"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.NavigationHintLatency">
+<histogram_suffixes name="ServiceWorker.NavigationHintLatency" separator="_">
   <suffix name="IsRunningNavigationHintTask"
       label="Starting a service worker for a navigation hint.">
     <obsolete>
@@ -91679,13 +92198,13 @@
   <affected-histogram name="Event.Latency.TouchToScrollUpdateSwapBegin"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.ShutdownStatus">
+<histogram_suffixes name="ServiceWorker.ShutdownStatus" separator="_">
   <suffix name="InShutdown" label="Browser shutdown started."/>
   <suffix name="NotInShutdown" label="Browser shutdown has not started."/>
   <affected-histogram name="ServiceWorker.ActivateEventStatus"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.StartSituation">
+<histogram_suffixes name="ServiceWorker.StartSituation" separator="_">
   <suffix name="DuringStartup"
       label="The worker started up during browser startup."/>
   <suffix name="NewProcess"
@@ -91705,7 +92224,7 @@
   <affected-histogram name="ServiceWorker.StartWorker.Time"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="ServiceWorker.WorkerPreparationMode">
+<histogram_suffixes name="ServiceWorker.WorkerPreparationMode" separator="_">
   <suffix name="StartWorkerDuringStartup"
       label="Started a worker during browser startup."/>
   <suffix name="StartWorkerNewProcess"
@@ -91803,7 +92322,7 @@
   <affected-histogram name="ServiceWorker.EventDispatchingDelay_UNKNOWN"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SessionRestoreTabCountMemoryPressure">
+<histogram_suffixes name="SessionRestoreTabCountMemoryPressure" separator="_">
   <suffix name="MemoryPressure"
       label="Total tabs involved in session restore that encountered memory
              pressure."/>
@@ -91825,7 +92344,7 @@
   <affected-histogram name="SessionRestore.TabCount"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SessionRestoreTabCounts">
+<histogram_suffixes name="SessionRestoreTabCounts" separator="_">
   <suffix name="1" label="1 tab present"/>
   <suffix name="2" label="2 tabs present"/>
   <suffix name="3" label="3 tabs present"/>
@@ -91854,7 +92373,7 @@
   <affected-histogram name="SessionRestore.ForegroundTabFirstPaint3"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SettingsResetPromptSettingType">
+<histogram_suffixes name="SettingsResetPromptSettingType" separator="_">
   <suffix name="DefaultSearch" label="Reset state for default search engine."/>
   <suffix name="StartupUrls" label="Reset state for startup URLs."/>
   <suffix name="Homepage" label="Reset state for homepage."/>
@@ -91886,7 +92405,7 @@
   <affected-histogram name="Startup.ShowAppListWarmStart"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SideloadWipeout">
+<histogram_suffixes name="SideloadWipeout" separator="_">
   <suffix name="Enabled" label="Sideload Wipeout Active."/>
   <suffix name="Disabled" label="Control group."/>
   <affected-histogram name="DisabledExtension.ExtensionWipedStatus"/>
@@ -91940,7 +92459,17 @@
   <affected-histogram name="Signin.Reconciler.Duration"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SimpleCacheWithOrWithoutIndex">
+<histogram_suffixes name="SigninAccountStatus" separator=".">
+  <suffix name="NewAccount" label="Using a new account, in the sign-in promo."/>
+  <suffix name="NotDefault"
+      label="Using not the default account, in the sign-in promo."/>
+  <suffix name="WithDefault"
+      label="Using the default account, in the sign-in promo."/>
+  <affected-histogram name="Signin.SigninCompletedAccessPoint"/>
+  <affected-histogram name="Signin.SigninStartedAccessPoint"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="SimpleCacheWithOrWithoutIndex" separator="_">
   <suffix name="WithIndex" label="The Simple Cache index was loaded."/>
   <suffix name="WithoutIndex"
       label="The Simple Cache index was not yet loaded."/>
@@ -91967,7 +92496,7 @@
   <affected-histogram name="Net.SSLProtocolErrorReason"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SocketType">
+<histogram_suffixes name="SocketType" separator="_">
   <obsolete>
     Deprecated as of 03/2015.
   </obsolete>
@@ -91995,7 +92524,7 @@
   <affected-histogram name="Net.SocketType"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SoftwareReporterEngine">
+<histogram_suffixes name="SoftwareReporterEngine" separator="_">
   <suffix name="Original"/>
   <suffix name="Experimental"/>
   <affected-histogram name="SoftwareReporter.FoundUwSReadError"/>
@@ -92011,7 +92540,7 @@
   <affected-histogram name="SoftwareReporter.Step"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SpdyCwnd">
+<histogram_suffixes name="SpdyCwnd" separator="_">
   <obsolete>
     Deprecated as of 07/2014.
   </obsolete>
@@ -92030,7 +92559,7 @@
   <affected-histogram name="PLT.StartToFinish_NormalLoad"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SpdyImpact">
+<histogram_suffixes name="SpdyImpact" separator="_">
   <suffix name="npn_with_http"
       label="with NPN negotiated but using HTTP instead of SPDY"/>
   <suffix name="npn_with_spdy" label="with NPN negotiated and using SPDY"/>
@@ -92105,7 +92634,7 @@
   <affected-histogram name="Sqlite.Vfs"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SSLFalseStart">
+<histogram_suffixes name="SSLFalseStart" separator="_">
   <obsolete>
     Removed 2011-06-01.
   </obsolete>
@@ -92117,7 +92646,7 @@
   <affected-histogram name="PLT.BeginToFinish_NormalLoad"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="StartupProfilingAbandonState">
+<histogram_suffixes name="StartupProfilingAbandonState" separator="_">
   <suffix name="NoPaint" label="Abandoned before first paint."/>
   <suffix name="NoLoad" label="Abandoned before first main frame load."/>
   <affected-histogram name="Startup.FirstWebContents.FinishReason"/>
@@ -92180,7 +92709,7 @@
   <affected-histogram name="Startup.FirstWebContents.MainNavigationStart"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="StartWorkerExistingProcess">
+<histogram_suffixes name="StartWorkerExistingProcess" separator="_">
   <suffix name="StartWorkerExistingProcess"
       label="The worker started up in an existing process"/>
   <affected-histogram name="ServiceWorker.NavigationPreload.ConcurrentTime"/>
@@ -92219,6 +92748,20 @@
   <affected-histogram name="Storage.Blob.SizeEvictedToDiskInKB"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="Storage.Bytes" separator=".">
+  <suffix name="DiskCache.AppCache" label="AppCache usage."/>
+  <suffix name="DiskCache.CacheStorage" label="CacheStorage usage."/>
+  <suffix name="DiskCache.ServiceWorker"
+      label="ServiceWorker scriptcache usage."/>
+  <suffix name="LevelDBEnv" label="Undifferentiated leveldb usage."/>
+  <suffix name="LevelDBEnv.IDB" label="IndexedDB usage."/>
+  <suffix name="LevelDBEnv.ServiceWorker"
+      label="ServiceWorker database usage."/>
+  <suffix name="MojoLevelDBEnv" label="Mojo leveldb component usage."/>
+  <affected-histogram name="Storage.BytesRead"/>
+  <affected-histogram name="Storage.BytesWritten"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="StunPingInternal" separator=".">
   <suffix name="0ms" label="0ms between requests"/>
   <suffix name="5ms" label="5ms between requests"/>
@@ -92246,10 +92789,15 @@
   <suffix name="SocialEngineeringAdsInterstitial"
       label="social eng ad blacklist pattern"/>
   <suffix name="PhishingInterstitial" label="phishing blacklist pattern"/>
-  <suffix name="SubresourceFilterOnly" label="subresource filter only patern"/>
+  <suffix name="SubresourceFilterOnly" label="subresource filter only pattern"/>
+  <affected-histogram name="SubresourceFilter.PageLoad.FinalURLMatch"/>
   <affected-histogram name="SubresourceFilter.PageLoad.RedirectChainLength"/>
   <affected-histogram
-      name="SubresourceFilter.PageLoad.RedirectChainMatchPattern"/>
+      name="SubresourceFilter.PageLoad.RedirectChainMatchPattern">
+    <obsolete>
+      Obsolete as of April 2017
+    </obsolete>
+  </affected-histogram>
 </histogram_suffixes>
 
 <histogram_suffixes name="SyncModelType" separator=".">
@@ -92292,7 +92840,7 @@
   <affected-histogram name="Sync.ModelTypeCount"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="SyzygyStartupTime">
+<histogram_suffixes name="SyzygyStartupTime" separator="_">
   <obsolete>
     No longer logged.
   </obsolete>
@@ -92348,12 +92896,15 @@
 
 <histogram_suffixes name="TabNewTabOnload" separator=".">
   <suffix name="Local" label="Local New Tab page."/>
+  <suffix name="LocalGoogle" label="Local New Tab page for Google."/>
+  <suffix name="LocalOther"
+      label="Local New Tab page for a non-Google provider."/>
   <suffix name="Google" label="New Tab page for Google."/>
   <suffix name="Other" label="New Tab page for a non-Google provider."/>
   <affected-histogram name="Tab.NewTabOnload"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Tabs.SwitchLatency">
+<histogram_suffixes name="Tabs.SwitchLatency" separator="_">
   <suffix name="Perceived"
       label="The time it takes to show something on the screen after the user
              selects a tab. This might be a fake snapshot or it might just be
@@ -92545,7 +93096,7 @@
       name="Net.QuicSession.LocallyTimedOutWithOpenStreams.TimeSinceLastReceived"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="UnPackConsumer">
+<histogram_suffixes name="UnPackConsumer" separator="_">
   <suffix name="ChromeArchivePatch"
       label="compressed patch: chrome_patch.packed.7z holding
              chrome_patch.diff (small)."/>
@@ -92651,13 +93202,13 @@
   <affected-histogram name="VRSessionVideoTime"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="WebApkType">
+<histogram_suffixes name="WebApkType" separator=".">
   <suffix name="BrowserApk" label="Installed by Chrome"/>
   <suffix name="UnboundApk" label="Not installed by Chrome"/>
   <affected-histogram name="WebApk.ShellApkVersion"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="WebFontFamily">
+<histogram_suffixes name="WebFontFamily" separator="_">
   <suffix name="roboto" label="Roboto font"/>
   <suffix name="opensans" label="Open Sans font"/>
   <suffix name="others" label="Fonts other than Roboto and Open Sans"/>
@@ -92732,7 +93283,7 @@
   <affected-histogram name="WebCore.WebSocket.MessageSize.Send"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="WebStoreLinkExperiment">
+<histogram_suffixes name="WebStoreLinkExperiment" separator="_">
   <suffix name="Disabled" label="Neither extra webstore link is visible"/>
   <suffix name="FooterLink" label="Link in bottom right of footer"/>
   <suffix name="PlusIcon" label="Plus icon in apps page"/>
@@ -92740,7 +93291,7 @@
   <affected-histogram name="NewTabPage.DefaultPageType"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="WeekdayNames">
+<histogram_suffixes name="WeekdayNames" separator="_">
   <suffix name="Monday"/>
   <suffix name="Tuesday"/>
   <suffix name="Wednesday"/>
@@ -92751,7 +93302,7 @@
   <affected-histogram name="NewTabPage.ContentSuggestions.UsageTimeLocal"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="WelcomeWin10Variant">
+<histogram_suffixes name="WelcomeWin10Variant" separator="_">
   <owner>tmartino@chromium.org</owner>
   <suffix name="InlineCombined" label="Inline layout style, combined promo"/>
   <suffix name="InlineDefault"
@@ -92826,6 +93377,7 @@
     </obsolete>
   </suffix>
   <suffix name="Cast"/>
+  <suffix name="BetaForum"/>
   <affected-histogram name="WrenchMenu.TimeToAction"/>
 </histogram_suffixes>
 
diff --git a/tools/metrics/histograms/print_style.py b/tools/metrics/histograms/print_style.py
index 6b70649..4e5efa1 100644
--- a/tools/metrics/histograms/print_style.py
+++ b/tools/metrics/histograms/print_style.py
@@ -32,6 +32,15 @@
     'with-suffix': ['name'],
 }
 
+# Attribute names that must be explicitly specified on nodes that support them.
+REQUIRED_ATTRIBUTES = [
+    # TODO(isherman): Make the 'label' attribute required as well. This requires
+    # fixing up existing suffixes that omit a label.
+    'name',
+    'separator',
+    'value',
+]
+
 # Tag names for top-level nodes whose children we don't want to indent.
 TAGS_THAT_DONT_INDENT = [
     'histogram-configuration',
@@ -72,6 +81,7 @@
 def GetPrintStyle():
   """Returns an XmlStyle object for pretty printing histograms."""
   return pretty_print_xml.XmlStyle(ATTRIBUTE_ORDER,
+                                   REQUIRED_ATTRIBUTES,
                                    TAGS_THAT_HAVE_EXTRA_NEWLINE,
                                    TAGS_THAT_DONT_INDENT,
                                    TAGS_THAT_ALLOW_SINGLE_LINE,
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 2b809c8..9996aba 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -46,7 +46,7 @@
       none of the field were autofilled. See |AutofillFormSubmittedState|.
     </summary>
   </metric>
-  <metric name="MillisecondsSinceFormLoaded">
+  <metric name="MillisecondsSinceFormParsed">
     <summary>
       Time since form parse.
     </summary>
@@ -78,7 +78,7 @@
 
 <event name="Autofill.SuggestionsShown">
   <owner>csashi@google.com</owner>
-  <metric name="MillisecondsSinceFormLoaded">
+  <metric name="MillisecondsSinceFormParsed">
     <summary>
       Time since form parse.
     </summary>
@@ -87,7 +87,7 @@
 
 <event name="Autofill.SelectedMaskedServerCard">
   <owner>csashi@google.com</owner>
-  <metric name="MillisecondsSinceFormLoaded">
+  <metric name="MillisecondsSinceFormParsed">
     <summary>
       Time since form parse.
     </summary>
@@ -100,7 +100,7 @@
     Recorded when user selects a suggestion and we fill the form with that
     suggestion.
   </summary>
-  <metric name="MillisecondsSinceFormLoaded">
+  <metric name="MillisecondsSinceFormParsed">
     <summary>
       Time since form parse.
     </summary>
@@ -146,7 +146,7 @@
       True whether field was autofilled. See |AutofillField.is_autofilled|.
     </summary>
   </metric>
-  <metric name="MillisecondsSinceFormLoaded">
+  <metric name="MillisecondsSinceFormParsed">
     <summary>
       Time since form parse.
     </summary>
@@ -159,6 +159,81 @@
   </metric>
 </event>
 
+<event name="ContextualSearch">
+  <owner>donnd@chromium.org</owner>
+  <summary>
+    Metrics related to a Contextual Search Tap event on a page, for use with
+    Ranker.  These metrics are recorded each time the user triggers the
+    Contextual Search UI via a tap gesture (when enabled).
+  </summary>
+  <metric name="DURATION_AFTER_SCROLL_MS">
+    <summary>
+      Duration in MS between showing the UI and a subsequent scroll event, or
+      not recorded if there was no subsequent scroll.
+    </summary>
+  </metric>
+  <metric name="DURATION_BEFORE_SCROLL_MS">
+    <summary>
+      Duration in MS between showing the most recent scroll event and showing
+      the UI, or 0 if no previous scroll event occurred.
+    </summary>
+  </metric>
+  <metric name="OUTCOME_WAS_PANEL_OPENED">
+    <summary>
+      Whether the user opened the overlay panel.  This is the primary outcome
+      metric.
+    </summary>
+  </metric>
+  <metric name="OUTCOME_WAS_QUICK_ACTION_CLICKED">
+    <summary>
+      Whether the user clicked within the overlay panel when a Quick-Action was
+      shown.  This is a secondary outcome metric.
+    </summary>
+  </metric>
+  <metric name="OUTCOME_WAS_QUICK_ANSWER_SEEN">
+    <summary>
+      Whether the user could see a Quick-Answer caption within the overlay
+      panel.  This is a tertiary outcome metric.
+    </summary>
+  </metric>
+  <metric name="PREVIOUS_28DAY_CTR_PERCENT">
+    <summary>
+      The CTR of the overlay panel for this user, aggregated over a previous 28
+      day period, expressed as an integer between 0-99.
+    </summary>
+  </metric>
+  <metric name="PREVIOUS_28DAY_IMPRESSIONS_COUNT">
+    <summary>
+      The count of views of the overlay panel for this user, aggregated over a
+      previous 28 day period.
+    </summary>
+  </metric>
+  <metric name="PREVIOUS_WEEK_CTR_PERCENT">
+    <summary>
+      The CTR of the overlay panel for this user, aggregated over the previous
+      week, expressed as an integer between 0-99.
+    </summary>
+  </metric>
+  <metric name="PREVIOUS_WEEK_IMPRESSIONS_COUNT">
+    <summary>
+      The count of views of the overlay panel for this user, aggregated over the
+      previous week.
+    </summary>
+  </metric>
+  <metric name="SCREEN_TOP_DPS">
+    <summary>
+      The location of the tap relative to the top of the screen, expressed in
+      DPs.
+    </summary>
+  </metric>
+  <metric name="WAS_SCREEN_BOTTOM">
+    <summary>
+      The location of the tap relative to the bottom of the screen, expressed as
+      an integer with 0 meaning not at the bottom and 1 meaning at the bottom.
+    </summary>
+  </metric>
+</event>
+
 <event name="PageLoad" singular="True">
   <owner>bmcquade@chromium.org</owner>
   <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 3408224..55b2e0f 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -15,9 +15,6 @@
 blink_perf.parser,"yukishiino@chromium.org, bashi@chromium.org, haraken@chromium.org",
 blink_perf.shadow_dom,hayato@chromium.org,
 blink_perf.svg,"kouhei@chromium.org, fs@opera.com",
-blink_style.key_mobile_sites,,
-blink_style.polymer,,
-blink_style.top_25,,
 blob_storage.blob_storage,,
 cc_perftests,enne@chromium.org,
 dromaeo.domcoreattr,"yukishiino@chromium.org, bashi@chromium.org, haraken@chromium.org",
@@ -27,10 +24,6 @@
 dummy_benchmark.noisy_benchmark_1,nednguyen@google.com,
 dummy_benchmark.stable_benchmark_1,nednguyen@google.com,
 gpu_perftests,reveman@chromium.org,
-gpu_times.gpu_rasterization.key_mobile_sites_smooth,,
-gpu_times.gpu_rasterization.top_25_smooth,,
-gpu_times.key_mobile_sites_smooth,,
-gpu_times.top_25_smooth,,
 image_decoding.image_decoding_measurement,"cblume@chromium.org, reveman@chromium.org",
 jetstream,"bmeurer@chromium.org, mvstanton@chromium.org",
 kraken,"bmeurer@chromium.org, mvstanton@chromium.org",
@@ -47,7 +40,6 @@
 memory.blink_memory_mobile,bashi@chromium.org,
 memory.desktop,erikchen@chromium.org,
 memory.dual_browser_test,perezju@chromium.org,
-memory.long_running_dual_browser_test,perezju@chromium.org,
 memory.long_running_idle_gmail_background_tbmv2,ulan@chromium.org,
 memory.long_running_idle_gmail_tbmv2,ulan@chromium.org,
 memory.top_10_mobile,perezju@chromium.org,
@@ -68,12 +60,8 @@
 power.android_acceptance,perezju@chromium.org,
 power.idle_platform,,
 power.steady_state,,
-power.top_10,,
-power.top_25,,
-power.tough_ad_cases,skyostil@chromium.org,
 power.trivial_pages,erikchen@chromium.org,
 power.typical_10_mobile,perezju@chromium.org,
-power.typical_10_mobile_reload,,
 rasterize_and_record_micro.key_mobile_sites,,
 rasterize_and_record_micro.key_silk_cases,vmpstr@chromium.org,
 rasterize_and_record_micro.partial_invalidation,,
@@ -155,7 +143,6 @@
 v8.browsing_mobile_classic,hablich@chromium.org,
 v8.browsing_mobile_turbo,mvstaton@chromium.org,
 v8.detached_context_age_in_gc,ulan@chromium.org,
-v8.google,hablich@chromium.org,
 v8.infinite_scroll-classic_tbmv2,hablich@chromium.org,
 v8.infinite_scroll-turbo_tbmv2,mvstaton@chromium.org,
 v8.infinite_scroll_tbmv2,ulan@chromium.org,
@@ -169,9 +156,4 @@
 v8.runtimestats.browsing_mobile,mythria@chromium.org,
 v8.runtimestats.browsing_mobile_classic,hablich@chromium.org,
 v8.runtimestats.browsing_mobile_turbo,mythria@chromium.org,
-webrtc.datachannel,phoglund@chromium.org,
-webrtc.getusermedia,,
-webrtc.peerconnection,,
-webrtc.stress,"ehmaldonado@chromium.org, phoglund@chromium.org",
-webrtc.webrtc_smoothness,qiangchen@chromium.org,
-webrtc.webrtc_smoothness_tbmv2,"ehmaldonado@chromium.org, phoglund@chromium.org, qiangchen@chromium.org",
+webrtc,"qiangchen@chromium.org, ehmaldonado@chromium.org, phoglund@chromium.org",
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index a30eeb0f..4543fbe 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -104,17 +104,10 @@
 
   for event_name in trace_events_to_measure:
     curr_test_runs_bound_index = 0
-    seen_uuids = set()
+    prev_event = None
     for event in model.IterAllEventsOfName(event_name):
-      # Trace events can be duplicated in some cases. Filter out trace events
-      # that have duplicated uuid.
-      event_uuid = None
-      if event.args:
-        event_uuid = event.args.get('uuid')
-      if event_uuid and event_uuid in seen_uuids:
+      if prev_event and prev_event.end >= event.start:
         continue
-      elif event_uuid:
-        seen_uuids.add(event_uuid)
       while (curr_test_runs_bound_index < len(test_runs_bounds) and
              event.start > test_runs_bounds[curr_test_runs_bound_index].max):
         curr_test_runs_bound_index += 1
@@ -130,6 +123,7 @@
         intersect_cpu_time = intersect_wall_time
       trace_cpu_time_metrics[event_name][curr_test_runs_bound_index] += (
           intersect_cpu_time)
+      prev_event = event
   return trace_cpu_time_metrics
 
 
@@ -259,11 +253,6 @@
   tag = 'bindings'
   subdir = 'Bindings'
 
-  @classmethod
-  def ShouldDisable(cls, possible_browser):
-    # http://crbug.com/563979
-    return cls.IsSvelte(possible_browser)
-
 
 @benchmark.Enabled('content-shell')
 class BlinkPerfBlinkGC(_BlinkPerfBenchmark):
diff --git a/tools/perf/benchmarks/blink_perf_unittest.py b/tools/perf/benchmarks/blink_perf_unittest.py
index 5d45a05..696ea098 100644
--- a/tools/perf/benchmarks/blink_perf_unittest.py
+++ b/tools/perf/benchmarks/blink_perf_unittest.py
@@ -271,3 +271,71 @@
         blink_perf._ComputeTraceEventsThreadTimeForBlinkPerf(
             model, renderer_main, ['foo', 'bar', 'baz']),
         {'foo': [15, 32], 'bar': [20, 0], 'baz': [0, 0]})
+
+  def testTraceEventMetricsNoDoubleCountingBasic(self):
+    model = model_module.TimelineModel()
+    renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+    renderer_main.name = 'CrRendererMain'
+
+    # Set up a main thread model that looks like:
+    #   [          blink_perf.run_test                     ]
+    #   |     [          foo           ]     [  foo  ]     |
+    #   |     [          foo           ]     |       |     |
+    #   |     |     [    foo     ]     |     |       |     |
+    #   |     |     |            |     |     |       |     |
+    #   100   120  140          400   420   440     510   550
+    #                     |                      |
+    # CPU dur of          |                      |
+    # of top most event:  280                    50
+    #
+    self._AddBlinkTestSlice(renderer_main, 100, 550)
+
+    renderer_main.BeginSlice('blink', 'foo', 120, 130)
+    renderer_main.BeginSlice('blink', 'foo', 120, 130)
+    renderer_main.BeginSlice('blink', 'foo', 140, 150)
+    renderer_main.EndSlice(400, 390)
+    renderer_main.EndSlice(420, 410)
+    renderer_main.EndSlice(420, 410)
+
+    renderer_main.BeginSlice('blink', 'foo', 440, 455)
+    renderer_main.EndSlice(510, 505)
+
+    self.assertEquals(
+        blink_perf._ComputeTraceEventsThreadTimeForBlinkPerf(
+            model, renderer_main, ['foo']), {'foo': [330]})
+
+
+  def testTraceEventMetricsNoDoubleCountingWithOtherSlidesMixedIn(self):
+    model = model_module.TimelineModel()
+    renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2)
+    renderer_main.name = 'CrRendererMain'
+
+    # Set up a main thread model that looks like:
+    #   [          blink_perf.run_test                                   ]
+    #   |     [          foo                 ]      [      bar     ]     |
+    #   |     |   [        bar         ]     |      |    [ foo  ]  |     |
+    #   |     |   |    [    foo     ]  |     |      |    |      |  |     |
+    #   |     |   |    |            |  |     |      |    |      |  |     |
+    #   100   120 130 140     |    400 405   420    440  480 | 510 520  550
+    #                         |                              |
+    # CPU dur of              |                              |
+    # of top most event:  280 (foo) & 270 (bar)            50 (bar) & 20 (foo)
+    #
+    self._AddBlinkTestSlice(renderer_main, 100, 550)
+
+    renderer_main.BeginSlice('blink', 'foo', 120, 130)
+    renderer_main.BeginSlice('blink', 'bar', 130, 135)
+    renderer_main.BeginSlice('blink', 'foo', 140, 150)
+    renderer_main.EndSlice(400, 390)
+    renderer_main.EndSlice(405, 405)
+    renderer_main.EndSlice(420, 410)
+
+    renderer_main.BeginSlice('blink', 'bar', 440, 455)
+    renderer_main.BeginSlice('blink', 'foo', 480, 490)
+    renderer_main.EndSlice(510, 510)
+    renderer_main.EndSlice(510, 505)
+
+    self.assertEquals(
+        blink_perf._ComputeTraceEventsThreadTimeForBlinkPerf(
+            model, renderer_main, ['foo', 'bar']),
+            {'foo': [300], 'bar': [320]})
diff --git a/tools/perf/benchmarks/blink_style.py b/tools/perf/benchmarks/blink_style.py
deleted file mode 100644
index 73e1929..0000000
--- a/tools/perf/benchmarks/blink_style.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from core import perf_benchmark
-
-from measurements import blink_style
-import page_sets
-from telemetry import benchmark
-
-
-@benchmark.Disabled('win8')
-class BlinkStyleTop25(perf_benchmark.PerfBenchmark):
-  """Measures performance of Blink's style engine (CSS Parsing, Style Recalc,
-  etc.) on the top 25 pages.
-  """
-  test = blink_style.BlinkStyle
-  page_set = page_sets.Top25PageSet
-
-  @classmethod
-  def Name(cls):
-    return 'blink_style.top_25'
-
-
-@benchmark.Enabled('android')
-class BlinkStyleKeyMobileSites(perf_benchmark.PerfBenchmark):
-  """Measures performance of Blink's style engine (CSS Parsing, Style Recalc,
-  etc.) on key mobile sites.
-  """
-  test = blink_style.BlinkStyle
-  page_set = page_sets.KeyMobileSitesPageSet
-
-  @classmethod
-  def ShouldDisable(cls, possible_browser):  # http://crbug.com/597656
-    return (possible_browser.browser_type == 'reference' and
-            possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X')
-
-  @classmethod
-  def Name(cls):
-    return 'blink_style.key_mobile_sites'
-
-
-@benchmark.Enabled('android')
-class BlinkStylePolymer(perf_benchmark.PerfBenchmark):
-  """Measures performance of Blink's style engine (CSS Parsing, Style Recalc,
-  etc.) for Polymer cases.
-  """
-  test = blink_style.BlinkStyle
-  page_set = page_sets.PolymerPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'blink_style.polymer'
diff --git a/tools/perf/benchmarks/gpu_times.py b/tools/perf/benchmarks/gpu_times.py
deleted file mode 100644
index 11487d9..0000000
--- a/tools/perf/benchmarks/gpu_times.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from core import perf_benchmark
-
-from benchmarks import silk_flags
-
-from telemetry import benchmark
-from telemetry.timeline import chrome_trace_category_filter
-from telemetry.web_perf.metrics import gpu_timeline
-from telemetry.web_perf import timeline_based_measurement
-
-import page_sets
-
-TOPLEVEL_CATEGORIES = ['disabled-by-default-gpu.device',
-                       'disabled-by-default-gpu.service']
-
-
-class _GPUTimes(perf_benchmark.PerfBenchmark):
-
-  def CreateTimelineBasedMeasurementOptions(self):
-    cat_string = ','.join(TOPLEVEL_CATEGORIES)
-    cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
-        cat_string)
-
-    options = timeline_based_measurement.Options(overhead_level=cat_filter)
-    options.SetLegacyTimelineBasedMetrics([gpu_timeline.GPUTimelineMetric()])
-    return options
-
-
-@benchmark.Disabled('all')  # http://crbug.com/453131, http://crbug.com/527543
-class GPUTimesKeyMobileSites(_GPUTimes):
-  """Measures GPU timeline metric on key mobile sites."""
-  page_set = page_sets.KeyMobileSitesSmoothPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'gpu_times.key_mobile_sites_smooth'
-
-
-@benchmark.Disabled('all')  # http://crbug.com/453131, http://crbug.com/527543
-class GPUTimesGpuRasterizationKeyMobileSites(_GPUTimes):
-  """Measures GPU timeline metric on key mobile sites with GPU rasterization.
-  """
-  page_set = page_sets.KeyMobileSitesSmoothPageSet
-
-  def SetExtraBrowserOptions(self, options):
-    silk_flags.CustomizeBrowserOptionsForGpuRasterization(options)
-
-  @classmethod
-  def Name(cls):
-    return 'gpu_times.gpu_rasterization.key_mobile_sites_smooth'
-
-
-@benchmark.Disabled('all')  # http://crbug.com/453131, http://crbug.com/517476
-class GPUTimesTop25Sites(_GPUTimes):
-  """Measures GPU timeline metric for the top 25 sites."""
-  page_set = page_sets.Top25SmoothPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'gpu_times.top_25_smooth'
-
-
-@benchmark.Disabled('all')  # http://crbug.com/453131, http://crbug.com/517476
-class GPUTimesGpuRasterizationTop25Sites(_GPUTimes):
-  """Measures GPU timeline metric for the top 25 sites with GPU rasterization.
-  """
-  page_set = page_sets.Top25SmoothPageSet
-
-  def SetExtraBrowserOptions(self, options):
-    silk_flags.CustomizeBrowserOptionsForGpuRasterization(options)
-
-  @classmethod
-  def Name(cls):
-    return 'gpu_times.gpu_rasterization.top_25_smooth'
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py
index 7c9540ae..8af2d32 100644
--- a/tools/perf/benchmarks/loading.py
+++ b/tools/perf/benchmarks/loading.py
@@ -37,6 +37,9 @@
         cache_temperatures=[cache_temperature.PCV1_COLD,
                             cache_temperature.PCV1_WARM,])
 
+  def GetExpectations(self):
+    return page_sets.LoadingDesktopExpectations()
+
   @classmethod
   def Name(cls):
     return 'loading.desktop'
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index d5b2122..8d3d76c 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -150,37 +150,6 @@
     return not _IGNORED_STATS_RE.search(value.name)
 
 
-# Benchmark disabled by default. Force to run with --also-run-disabled-tests.
-@benchmark.Disabled('all')
-@benchmark.Owner(emails=['perezju@chromium.org'])
-class LongRunningDualBrowserBenchmark(_MemoryInfra):
-  """Measures memory during prolonged usage of alternating browsers.
-
-  Same as memory.dual_browser_test, but the test is run for 60 iterations
-  and the browser is *not* restarted between page set repeats.
-  """
-  page_set = page_sets.DualBrowserStorySet
-  options = {'pageset_repeat': 60}
-
-  @classmethod
-  def Name(cls):
-    return 'memory.long_running_dual_browser_test'
-
-  @classmethod
-  def ShouldTearDownStateAfterEachStoryRun(cls):
-    return False
-
-  @classmethod
-  def ShouldTearDownStateAfterEachStorySetRun(cls):
-    return False
-
-  @classmethod
-  def ValueCanBeAddedPredicate(cls, value, is_first_result):
-    # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard
-    # is able to cope with the data load generated by TBMv2 metrics.
-    return not _IGNORED_STATS_RE.search(value.name)
-
-
 @benchmark.Enabled('android')  # catapult:#3176
 @benchmark.Owner(emails=['bashi@chromium.org'])
 class RendererMemoryBlinkMemoryMobile(_MemoryInfra):
diff --git a/tools/perf/benchmarks/oopif.py b/tools/perf/benchmarks/oopif.py
new file mode 100644
index 0000000..73d70d3
--- /dev/null
+++ b/tools/perf/benchmarks/oopif.py
@@ -0,0 +1,91 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(rnephew): Migrate to loading benchmark harness.
+from core import perf_benchmark
+import page_sets
+
+from telemetry import benchmark
+from telemetry.page import cache_temperature
+from telemetry.web_perf import timeline_based_measurement
+
+
+def AugmentOptionsForLoadingMetrics(tbm_options):
+  cat_filter = tbm_options.config.chrome_trace_config.category_filter
+
+  # "blink.console" is used for marking ranges in
+  # cache_temperature.MarkTelemetryInternal.
+  cat_filter.AddIncludedCategory('blink.console')
+
+  # "navigation" and "blink.user_timing" are needed to capture core
+  # navigation events.
+  cat_filter.AddIncludedCategory('navigation')
+  cat_filter.AddIncludedCategory('blink.user_timing')
+
+  # "loading" is needed for first-meaningful-paint computation.
+  cat_filter.AddIncludedCategory('loading')
+
+  # "toplevel" category is used to capture TaskQueueManager events
+  # necessary to compute time-to-interactive.
+  cat_filter.AddIncludedCategory('toplevel')
+
+  tbm_options.AddTimelineBasedMetric('loadingMetric')
+  return tbm_options
+
+
+class _OopifBase(perf_benchmark.PerfBenchmark):
+  options = {'pageset_repeat': 2}
+
+  def CreateTimelineBasedMeasurementOptions(self):
+    tbm_options = timeline_based_measurement.Options()
+    AugmentOptionsForLoadingMetrics(tbm_options)
+    return tbm_options
+
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    # crbug.com/619254
+    if possible_browser.browser_type == 'reference':
+      return True
+
+    # crbug.com/616781
+    if (cls.IsSvelte(possible_browser) or
+        possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X' or
+        possible_browser.platform.GetDeviceTypeName() == 'AOSP on BullHead'):
+      return True
+
+    return False
+
+
+@benchmark.Disabled('reference', 'android')
+@benchmark.Owner(emails=['nasko@chromium.org'])
+class PageCyclerV2BasicOopifIsolated(_OopifBase):
+  """ A benchmark measuring performance of out-of-process iframes. """
+  page_set = page_sets.OopifBasicPageSet
+
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_v2_site_isolation.basic_oopif'
+
+  def SetExtraBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs(['--site-per-process'])
+
+  def CreateStorySet(self, options):
+    return page_sets.OopifBasicPageSet(cache_temperatures=[
+          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
+
+
+@benchmark.Disabled('android')
+@benchmark.Owner(emails=['nasko@chromium.org'])
+class PageCyclerV2BasicOopif(_OopifBase):
+  """ A benchmark measuring performance of the out-of-process iframes page
+  set, without running in out-of-process iframes mode.. """
+  page_set = page_sets.OopifBasicPageSet
+
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_v2.basic_oopif'
+
+  def CreateStorySet(self, options):
+    return page_sets.OopifBasicPageSet(cache_temperatures=[
+          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
diff --git a/tools/perf/benchmarks/page_cycler_v2.py b/tools/perf/benchmarks/page_cycler_v2.py
index e1127e2..6915f0e 100644
--- a/tools/perf/benchmarks/page_cycler_v2.py
+++ b/tools/perf/benchmarks/page_cycler_v2.py
@@ -183,36 +183,3 @@
     return page_sets.Top10MobilePageSet(run_no_page_interactions=True,
         cache_temperatures=[
             cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
-
-
-@benchmark.Disabled('reference', 'android')
-@benchmark.Owner(emails=['nasko@chromium.org'])
-class PageCyclerV2BasicOopifIsolated(_PageCyclerV2):
-  """ A benchmark measuring performance of out-of-process iframes. """
-  page_set = page_sets.OopifBasicPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'page_cycler_v2_site_isolation.basic_oopif'
-
-  def SetExtraBrowserOptions(self, options):
-    options.AppendExtraBrowserArgs(['--site-per-process'])
-
-  def CreateStorySet(self, options):
-    return page_sets.OopifBasicPageSet(cache_temperatures=[
-          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
-
-@benchmark.Disabled('android')
-@benchmark.Owner(emails=['nasko@chromium.org'])
-class PageCyclerV2BasicOopif(_PageCyclerV2):
-  """ A benchmark measuring performance of the out-of-process iframes page
-  set, without running in out-of-process iframes mode.. """
-  page_set = page_sets.OopifBasicPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'page_cycler_v2.basic_oopif'
-
-  def CreateStorySet(self, options):
-    return page_sets.OopifBasicPageSet(cache_temperatures=[
-          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index 7cc17e1..ae2b4760 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -50,93 +50,6 @@
   def Name(cls):
     return 'power.typical_10_mobile'
 
-# This benchmark runs only on android but it is disabled on android as well
-# because of http://crbug.com/683238
-# @benchmark.Enabled('android')
-@benchmark.Disabled('all')
-@benchmark.Disabled('android-webview')  # http://crbug.com/622300
-@benchmark.Owner(emails=['skyostil@chromium.org'])
-class PowerToughAdCases(perf_benchmark.PerfBenchmark):
-  """Android power test with tough ad pages."""
-  test = power.Power
-  page_set = page_sets.ToughAdCasesPageSet
-
-  def SetExtraBrowserOptions(self, options):
-    options.full_performance_mode = False
-
-  @classmethod
-  def Name(cls):
-    return 'power.tough_ad_cases'
-
-  @classmethod
-  def ShouldDisable(cls, possible_browser):
-     # http://crbug.com/563968, http://crbug.com/593973
-    return (cls.IsSvelte(possible_browser) or
-      (possible_browser.browser_type ==  'reference' and
-       possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X'))
-
-
-@benchmark.Enabled('android')
-@benchmark.Disabled('all')
-class PowerTypical10MobileReload(perf_benchmark.PerfBenchmark):
-  """Android typical 10 mobile power reload test."""
-  test = power.LoadPower
-  page_set = page_sets.Typical10MobileReloadPageSet
-
-  def SetExtraBrowserOptions(self, options):
-    options.full_performance_mode = False
-
-  @classmethod
-  def Name(cls):
-    return 'power.typical_10_mobile_reload'
-
-
-@benchmark.Enabled('mac')
-class PowerTop10(perf_benchmark.PerfBenchmark):
-  """Top 10 quiescent power test."""
-  test = power.QuiescentPower
-  page_set = page_sets.Top10QuiescentPageSet
-
-  def SetExtraBrowserOptions(self, options):
-    options.full_performance_mode = False
-
-  @classmethod
-  def Name(cls):
-    return 'power.top_10'
-
-
-@benchmark.Enabled('mac')
-class PowerTop25(perf_benchmark.PerfBenchmark):
-  """Top 25 quiescent power test."""
-  test = power.QuiescentPower
-  page_set = page_sets.Top25PageSet
-
-  def SetExtraBrowserOptions(self, options):
-    options.full_performance_mode = False
-
-  @classmethod
-  def Name(cls):
-    return 'power.top_25'
-
-  def CreateStorySet(self, _):
-    stories = self.page_set()
-    to_remove = [x for x in stories if self.IsPageNotQuiescent(x.url)]
-    for story in to_remove:
-      stories.RemoveStory(story)
-    return stories
-
-  @staticmethod
-  def IsPageNotQuiescent(page_url):
-    # Exclude sites not suitable for this benchmark because they do not
-    # consistently become quiescent within 60 seconds.
-    non_quiescent_urls = [
-      'techcrunch.com',
-      'docs.google.com',
-      'plus.google.com'
-    ]
-
-    return any(url in page_url for url in non_quiescent_urls)
-
 
 @benchmark.Enabled('mac')
 @benchmark.Owner(emails=['erikchen@chromium.org'])
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index 5ca5cde..d8699282 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -1,33 +1,19 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-import os
-
-from core import path_util
 from core import perf_benchmark
-from page_sets import google_pages
 
 from benchmarks import v8_helper
 
 from measurements import v8_detached_context_age_in_gc
 import page_sets
+
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.timeline import chrome_trace_config
 from telemetry.web_perf import timeline_based_measurement
 
 
-def CreateV8TimelineBasedMeasurementOptions():
-  category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
-  category_filter.AddIncludedCategory('v8')
-  category_filter.AddIncludedCategory('blink.console')
-  category_filter.AddDisabledByDefault('disabled-by-default-v8.compile')
-  options = timeline_based_measurement.Options(category_filter)
-  options.SetTimelineBasedMetrics(['executionMetric'])
-  return options
-
-
 @benchmark.Owner(emails=['ulan@chromium.org'])
 class V8DetachedContextAgeInGC(perf_benchmark.PerfBenchmark):
   """Measures the number of GCs needed to collect a detached context.
@@ -186,45 +172,6 @@
   def Name(cls):
     return 'v8.mobile_infinite_scroll-classic_tbmv2'
 
-@benchmark.Owner(emails=['hablich@chromium.org'])
-class V8Adword(perf_benchmark.PerfBenchmark):
-  """Measures V8 Execution metrics on the Adword page."""
-
-  options = {'pageset_repeat': 3}
-
-  def CreateTimelineBasedMeasurementOptions(self):
-    return CreateV8TimelineBasedMeasurementOptions()
-
-  def CreateStorySet(self, options):
-    """Creates the instance of StorySet used to run the benchmark.
-
-    Can be overridden by subclasses.
-    """
-    story_set = story.StorySet(
-        archive_data_file=os.path.join(
-            path_util.GetPerfStorySetsDir(), 'data', 'v8_pages.json'),
-        cloud_storage_bucket=story.PARTNER_BUCKET)
-    story_set.AddStory(google_pages.AdwordCampaignDesktopPage(story_set))
-    return story_set
-
-  @classmethod
-  def Name(cls):
-    return 'v8.google'
-
-  @classmethod
-  def ShouldDisable(cls, possible_browser):
-    if cls.IsSvelte(possible_browser): # http://crbug.com/596556
-      return True
-    # http://crbug.com/623576
-    if (possible_browser.platform.GetDeviceTypeName() == 'Nexus 5' or
-        possible_browser.platform.GetDeviceTypeName() == 'Nexus 7'):
-      return True
-    return False
-
-  @classmethod
-  def ShouldTearDownStateAfterEachStoryRun(cls):
-    return True
-
 
 class _Top25RuntimeStats(perf_benchmark.PerfBenchmark):
   options = {'pageset_repeat': 3}
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index 5613c74..67d48bbc 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -226,8 +226,6 @@
 
 
 @benchmark.Owner(emails=['mythria@chromium.org'])
-@benchmark.Disabled('win')  # http://crbug.com/704197
-@benchmark.Disabled('android')
 class V8RuntimeStatsDesktopBrowsingBenchmark(
     _V8RuntimeStatsBrowsingBenchmark):
   PLATFORM = 'desktop'
@@ -254,8 +252,6 @@
     return 'v8.runtimestats.browsing_desktop_turbo'
 
 
-@benchmark.Disabled('win')  # http://crbug.com/704197
-@benchmark.Disabled('android')
 @benchmark.Owner(emails=['hablich@chromium.org'])
 class V8RuntimeStatsDesktopClassicBrowsingBenchmark(
     _V8RuntimeStatsBrowsingBenchmark):
diff --git a/tools/perf/benchmarks/webrtc.py b/tools/perf/benchmarks/webrtc.py
index ea1e127..6f073d5 100644
--- a/tools/perf/benchmarks/webrtc.py
+++ b/tools/perf/benchmarks/webrtc.py
@@ -4,115 +4,37 @@
 
 from core import perf_benchmark
 
-from measurements import webrtc
 import page_sets
 from telemetry import benchmark
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.web_perf import timeline_based_measurement
-from telemetry.web_perf.metrics import webrtc_rendering_timeline
-
-RENDERING_VALUE_PREFIX = 'WebRTCRendering_'
-
-# TODO(qyearsley, mcasas): Add webrtc.audio when http://crbug.com/468732
-# is fixed, or revert https://codereview.chromium.org/1544573002/ when
-# http://crbug.com/568333 is fixed.
 
 
-class _Webrtc(perf_benchmark.PerfBenchmark):
+@benchmark.Owner(emails=['qiangchen@chromium.org', # For smoothness metrics
+                         'ehmaldonado@chromium.org',
+                         'phoglund@chromium.org'])
+class WebrtcPerfBenchmark(perf_benchmark.PerfBenchmark):
   """Base class for WebRTC metrics for real-time communications tests."""
-  test = webrtc.WebRTC
-
-
-class WebrtcGetusermedia(_Webrtc):
-  """Measures WebRtc GetUserMedia for video capture and local playback."""
-  page_set = page_sets.WebrtcGetusermediaPageSet
+  page_set = page_sets.WebrtcPageSet
 
   @classmethod
   def Name(cls):
-    return 'webrtc.getusermedia'
-
-
-class WebrtcPeerConnection(_Webrtc):
-  """Measures WebRtc Peerconnection for remote video and audio communication."""
-  page_set = page_sets.WebrtcPeerconnectionPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'webrtc.peerconnection'
-
-
-@benchmark.Owner(emails=['phoglund@chromium.org'])
-class WebrtcDataChannel(_Webrtc):
-  """Measures WebRtc DataChannel loopback."""
-  page_set = page_sets.WebrtcDatachannelPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'webrtc.datachannel'
-
-
-@benchmark.Disabled('win')
-@benchmark.Owner(emails=['ehmaldonado@chromium.org', 'phoglund@chromium.org'])
-class WebrtcStressTest(perf_benchmark.PerfBenchmark):
-  """Measures WebRtc CPU and GPU usage with multiple peer connections."""
-  page_set = page_sets.WebrtcStresstestPageSet
-
-  @classmethod
-  def Name(cls):
-    return 'webrtc.stress'
-
-  def CreatePageTest(self, options):
-    # Exclude all stats.
-    return webrtc.WebRTC(particular_metrics=['googAvgEncodeMs',
-                                             'googFrameRateReceived'])
-
-
-# WebrtcRendering must be a PerfBenchmark, and not a _Webrtc, because it is a
-# timeline-based.
-# Disabled on reference builds because they crash and don't support tab
-# capture. See http://crbug.com/603232.
-@benchmark.Disabled('reference')
-@benchmark.Disabled('android')  # http://crbug.com/610019
-@benchmark.Owner(emails=['qiangchen@chromium.org'])
-class WebrtcRendering(perf_benchmark.PerfBenchmark):
-  """Specific time measurements (e.g. fps, smoothness) for WebRtc rendering."""
-
-  page_set = page_sets.WebrtcRenderingPageSet
+    return 'webrtc'
 
   def CreateTimelineBasedMeasurementOptions(self):
+    categories = [
+        # Disable all categories by default.
+        '-*',
+        'toplevel',
+        # WebRTC
+        'webrtc',
+    ]
+
     category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
-        filter_string='webrtc,webkit.console,blink.console')
-    options = timeline_based_measurement.Options(category_filter)
-    options.SetLegacyTimelineBasedMetrics(
-        [webrtc_rendering_timeline.WebRtcRenderingTimelineMetric()])
-    return options
-
-  def SetExtraBrowserOptions(self, options):
-    options.AppendExtraBrowserArgs('--use-fake-device-for-media-stream')
-    options.AppendExtraBrowserArgs('--use-fake-ui-for-media-stream')
-
-  @classmethod
-  def Name(cls):
-    return 'webrtc.webrtc_smoothness'
-
-
-# WebrtcRenderingTBMv2 must be a PerfBenchmark, and not a _Webrtc, because it is
-# a timeline-based metric.
-@benchmark.Owner(emails=['ehmaldonado@chromium.org',
-                         'phoglund@chromium.org',
-                         'qiangchen@chromium.org'])
-class WebrtcRenderingTBMv2(perf_benchmark.PerfBenchmark):
-  """Specific time measurements (e.g. fps, smoothness) for WebRtc rendering."""
-
-  page_set = page_sets.WebrtcRenderingPageSet
-
-  def CreateTimelineBasedMeasurementOptions(self):
-    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
-        filter_string='webrtc,toplevel')
+        filter_string=','.join(categories))
     options = timeline_based_measurement.Options(category_filter)
     options.SetTimelineBasedMetrics([
         'cpuTimeMetric',
-        'expectedQueueingTimeMetric',
         'webrtcRenderingMetric',
     ])
     return options
@@ -120,7 +42,3 @@
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--use-fake-device-for-media-stream')
     options.AppendExtraBrowserArgs('--use-fake-ui-for-media-stream')
-
-  @classmethod
-  def Name(cls):
-    return 'webrtc.webrtc_smoothness_tbmv2'
diff --git a/tools/perf/clear_system_cache/BUILD.gn b/tools/perf/clear_system_cache/BUILD.gn
index 3072d32..f3d1c38 100644
--- a/tools/perf/clear_system_cache/BUILD.gn
+++ b/tools/perf/clear_system_cache/BUILD.gn
@@ -12,7 +12,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//build/config/sanitizers:deps",
+    "//build/config:exe_and_shlib_deps",
     "//build/win:default_exe_manifest",
   ]
 }
diff --git a/tools/perf/contrib/cros_benchmarks/OWNERS b/tools/perf/contrib/cros_benchmarks/OWNERS
new file mode 100644
index 0000000..d9523a3
--- /dev/null
+++ b/tools/perf/contrib/cros_benchmarks/OWNERS
@@ -0,0 +1,5 @@
+bccheng@chromium.org
+deanliao@chromium.org
+vovoy@chromium.org
+lozano@chromium.org
+laszio@chromium.org
diff --git a/tools/perf/contrib/memory_long_running/OWNERS b/tools/perf/contrib/memory_long_running/OWNERS
new file mode 100644
index 0000000..e15131b
--- /dev/null
+++ b/tools/perf/contrib/memory_long_running/OWNERS
@@ -0,0 +1,3 @@
+hjd@chromium.org
+perezju@chromium.org
+primiano@chromium.org
diff --git a/tools/perf/contrib/memory_long_running/__init__.py b/tools/perf/contrib/memory_long_running/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/perf/contrib/memory_long_running/__init__.py
diff --git a/tools/perf/contrib/memory_long_running/memory_long_running.py b/tools/perf/contrib/memory_long_running/memory_long_running.py
new file mode 100644
index 0000000..e33f751
--- /dev/null
+++ b/tools/perf/contrib/memory_long_running/memory_long_running.py
@@ -0,0 +1,38 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from benchmarks import memory
+import page_sets
+
+from telemetry import benchmark
+
+
+# pylint: disable=protected-access
+@benchmark.Owner(emails=['perezju@chromium.org'])
+class LongRunningDualBrowserBenchmark(memory._MemoryInfra):
+  """Measures memory during prolonged usage of alternating browsers.
+
+  Same as memory.dual_browser_test, but the test is run for 60 iterations
+  and the browser is *not* restarted between page set repeats.
+  """
+  page_set = page_sets.DualBrowserStorySet
+  options = {'pageset_repeat': 60}
+
+  @classmethod
+  def Name(cls):
+    return 'memory.long_running_dual_browser_test'
+
+  @classmethod
+  def ShouldTearDownStateAfterEachStoryRun(cls):
+    return False
+
+  @classmethod
+  def ShouldTearDownStateAfterEachStorySetRun(cls):
+    return False
+
+  @classmethod
+  def ValueCanBeAddedPredicate(cls, value, is_first_result):
+    # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard
+    # is able to cope with the data load generated by TBMv2 metrics.
+    return not memory._IGNORED_STATS_RE.search(value.name)
diff --git a/tools/perf/core/benchmark_sharding_map.json b/tools/perf/core/benchmark_sharding_map.json
index 3482230a..360475908 100644
--- a/tools/perf/core/benchmark_sharding_map.json
+++ b/tools/perf/core/benchmark_sharding_map.json
@@ -1,4 +1,235 @@
 {
+  "Android Nexus5 Perf": {
+    "build13-b1--device1": {
+      "benchmarks": [
+        "smoothness.key_silk_cases",
+        "system_health.memory_desktop",
+        "system_health.memory_mobile"
+      ]
+    },
+    "build13-b1--device2": {
+      "benchmarks": [
+        "loading.desktop",
+        "smoothness.simple_mobile_sites",
+        "v8.browsing_desktop_classic"
+      ]
+    },
+    "build13-b1--device3": {
+      "benchmarks": [
+        "page_cycler_v2.intl_ja_zh",
+        "v8.runtimestats.browsing_mobile_classic"
+      ]
+    },
+    "build13-b1--device4": {
+      "benchmarks": [
+        "blink_perf.blink_gc",
+        "page_cycler_v2.typical_25",
+        "v8.infinite_scroll-turbo_tbmv2"
+      ]
+    },
+    "build13-b1--device5": {
+      "benchmarks": [
+        "system_health.common_desktop",
+        "v8.browsing_mobile",
+        "v8.browsing_mobile_turbo"
+      ]
+    },
+    "build13-b1--device6": {
+      "benchmarks": [
+        "dromaeo.domcoretraverse",
+        "memory.desktop",
+        "power.typical_10_mobile",
+        "smoothness.tough_animation_cases",
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
+      ]
+    },
+    "build13-b1--device7": {
+      "benchmarks": [
+        "blink_perf.shadow_dom",
+        "dromaeo.domcorequery",
+        "memory.blink_memory_mobile",
+        "page_cycler_v2.intl_ko_th_vi",
+        "power.idle_platform",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "start_with_ext.warm.blank_page",
+        "v8.browsing_mobile_classic"
+      ]
+    },
+    "build14-b1--device1": {
+      "benchmarks": [
+        "battor.trivial_pages",
+        "media.tough_video_cases_tbmv2",
+        "octane",
+        "smoothness.gpu_rasterization.tough_scrolling_cases",
+        "smoothness.tough_filters_cases",
+        "thread_times.key_hit_test_cases",
+        "thread_times.key_idle_power_cases",
+        "tracing.tracing_with_debug_overhead",
+        "v8.infinite_scroll-classic_tbmv2",
+        "v8.runtimestats.browsing_mobile"
+      ]
+    },
+    "build14-b1--device2": {
+      "benchmarks": [
+        "dummy_benchmark.noisy_benchmark_1",
+        "jetstream",
+        "page_cycler_v2.intl_hi_ru",
+        "smoothness.tough_texture_upload_cases",
+        "speedometer"
+      ]
+    },
+    "build14-b1--device3": {
+      "benchmarks": [
+        "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.image_decoding_cases",
+        "smoothness.pathological_mobile_sites",
+        "smoothness.tough_pinch_zoom_cases",
+        "startup.large_profile.cold.blank_page",
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
+      ]
+    },
+    "build14-b1--device4": {
+      "benchmarks": [
+        "blink_perf.bindings",
+        "blink_perf.canvas",
+        "memory.dual_browser_test",
+        "page_cycler_v2.intl_es_fr_pt-BR",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.gpu_rasterization.polymer",
+        "start_with_url.cold.startup_pages",
+        "startup.warm.blank_page",
+        "startup.warm.chrome_signin",
+        "system_health.webview_startup",
+        "v8.browsing_desktop_turbo"
+      ]
+    },
+    "build14-b1--device5": {
+      "benchmarks": [
+        "blink_perf.layout",
+        "dromaeo.domcoreattr",
+        "oortonline_tbmv2",
+        "page_cycler_v2.intl_ar_fa_he",
+        "power.android_acceptance",
+        "smoothness.maps",
+        "smoothness.tough_webgl_cases",
+        "thread_times.simple_mobile_sites"
+      ]
+    },
+    "build14-b1--device6": {
+      "benchmarks": [
+        "battor.steady_state",
+        "blink_perf.svg",
+        "blob_storage.blob_storage",
+        "media.android.tough_video_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
+        "rasterize_and_record_micro.polymer",
+        "smoothness.gpu_rasterization.top_25_smooth",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
+        "thread_times.key_noop_cases",
+        "thread_times.polymer",
+        "v8.mobile_infinite_scroll-turbo_tbmv2",
+        "v8.runtimestats.browsing_mobile_turbo"
+      ]
+    },
+    "build14-b1--device7": {
+      "benchmarks": [
+        "image_decoding.image_decoding_measurement",
+        "media.mse_cases",
+        "memory.long_running_idle_gmail_tbmv2",
+        "smoothness.scrolling_tough_ad_cases",
+        "speedometer-classic",
+        "system_health.common_mobile",
+        "v8.infinite_scroll_tbmv2"
+      ]
+    },
+    "build48-b1--device1": {
+      "benchmarks": [
+        "loading.mobile",
+        "media.android.tough_video_cases_tbmv2",
+        "media.tough_video_cases",
+        "service_worker.service_worker",
+        "smoothness.tough_webgl_ad_cases",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
+      ]
+    },
+    "build48-b1--device2": {
+      "benchmarks": [
+        "blink_perf.events",
+        "dummy_benchmark.stable_benchmark_1",
+        "power.trivial_pages",
+        "smoothness.top_25_smooth",
+        "smoothness.tough_ad_cases",
+        "startup.large_profile.warm.blank_page"
+      ]
+    },
+    "build48-b1--device3": {
+      "benchmarks": [
+        "dromaeo.domcoremodify",
+        "media.media_cns_cases",
+        "memory.top_10_mobile_stress",
+        "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.key_desktop_move_cases",
+        "smoothness.sync_scroll.key_mobile_sites_smooth",
+        "thread_times.tough_compositor_cases",
+        "thread_times.tough_scrolling_cases"
+      ]
+    },
+    "build48-b1--device4": {
+      "benchmarks": [
+        "blink_perf.dom",
+        "page_cycler_v2.basic_oopif",
+        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_canvas_cases",
+        "speedometer-turbo",
+        "start_with_ext.cold.blank_page",
+        "storage.indexeddb_endure",
+        "system_health.webview_startup_multiprocess",
+        "thread_times.key_silk_cases"
+      ]
+    },
+    "build48-b1--device5": {
+      "benchmarks": [
+        "blink_perf.css",
+        "blink_perf.parser",
+        "page_cycler_v2.top_10_mobile",
+        "rasterize_and_record_micro.key_silk_cases",
+        "scheduler.tough_scheduling_cases",
+        "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "smoothness.tough_image_decode_cases",
+        "start_with_url.warm.startup_pages",
+        "v8.mobile_infinite_scroll-classic_tbmv2",
+        "v8.mobile_infinite_scroll_tbmv2",
+        "v8.runtimestats.browsing_desktop_turbo"
+      ]
+    },
+    "build48-b1--device6": {
+      "benchmarks": [
+        "blink_perf.paint",
+        "kraken",
+        "power.steady_state",
+        "smoothness.key_mobile_sites_smooth",
+        "startup.cold.blank_page",
+        "tracing.tracing_with_background_memory_infra"
+      ]
+    },
+    "build48-b1--device7": {
+      "benchmarks": [
+        "oortonline",
+        "rasterize_and_record_micro.key_mobile_sites",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.tough_path_rendering_cases",
+        "smoothness.tough_scrolling_cases",
+        "v8.runtime_stats.top_25",
+        "v8.runtimestats.browsing_desktop",
+        "v8.runtimestats.browsing_desktop_classic"
+      ]
+    }
+  },
   "Android Nexus5X Perf": {
     "build73-b1--device1": {
       "benchmarks": [
@@ -17,7 +248,6 @@
     "build73-b1--device3": {
       "benchmarks": [
         "page_cycler_v2.intl_ja_zh",
-        "power.typical_10_mobile_reload",
         "v8.runtimestats.browsing_mobile_classic"
       ]
     },
@@ -30,9 +260,6 @@
     },
     "build73-b1--device5": {
       "benchmarks": [
-        "blink_style.key_mobile_sites",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "gpu_times.gpu_rasterization.top_25_smooth",
         "system_health.common_desktop",
         "v8.browsing_mobile",
         "v8.browsing_mobile_turbo"
@@ -40,107 +267,98 @@
     },
     "build73-b1--device6": {
       "benchmarks": [
-        "blink_style.polymer",
         "dromaeo.domcoretraverse",
         "memory.desktop",
         "power.typical_10_mobile",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.tough_animation_cases",
-        "thread_times.key_mobile_sites_smooth"
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
       ]
     },
     "build73-b1--device7": {
       "benchmarks": [
         "blink_perf.shadow_dom",
+        "dromaeo.domcorequery",
         "memory.blink_memory_mobile",
         "page_cycler_v2.intl_ko_th_vi",
         "power.idle_platform",
-        "smoothness.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "start_with_ext.warm.blank_page",
-        "thread_times.key_hit_test_cases",
-        "v8.browsing_mobile_classic",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.browsing_mobile_classic"
       ]
     },
     "build74-b1--device1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.canvas",
-        "dummy_benchmark.noisy_benchmark_1",
         "media.tough_video_cases_tbmv2",
+        "octane",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "smoothness.tough_filters_cases",
+        "thread_times.key_hit_test_cases",
         "thread_times.key_idle_power_cases",
+        "tracing.tracing_with_debug_overhead",
         "v8.infinite_scroll-classic_tbmv2",
-        "v8.runtimestats.browsing_mobile",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_mobile"
       ]
     },
     "build74-b1--device2": {
       "benchmarks": [
-        "oortonline",
+        "dummy_benchmark.noisy_benchmark_1",
+        "jetstream",
         "page_cycler_v2.intl_hi_ru",
-        "power.tough_ad_cases",
-        "rasterize_and_record_micro.partial_invalidation",
-        "smoothness.gpu_rasterization.tough_filters_cases",
-        "thread_times.tough_compositor_cases"
+        "smoothness.tough_texture_upload_cases",
+        "speedometer"
       ]
     },
     "build74-b1--device3": {
       "benchmarks": [
-        "blink_perf.bindings",
-        "dromaeo.domcorequery",
-        "media.media_cns_cases",
         "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.pathological_mobile_sites",
         "smoothness.tough_pinch_zoom_cases",
         "startup.large_profile.cold.blank_page",
-        "sunspider"
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
       ]
     },
     "build74-b1--device4": {
       "benchmarks": [
-        "gpu_times.key_mobile_sites_smooth",
+        "blink_perf.bindings",
+        "blink_perf.canvas",
         "memory.dual_browser_test",
-        "octane",
         "page_cycler_v2.intl_es_fr_pt-BR",
-        "power.top_10",
+        "rasterize_and_record_micro.partial_invalidation",
         "smoothness.gpu_rasterization.polymer",
-        "smoothness.tough_image_decode_cases",
         "start_with_url.cold.startup_pages",
+        "startup.warm.blank_page",
         "startup.warm.chrome_signin",
         "system_health.webview_startup",
-        "tab_switching.typical_25",
         "v8.browsing_desktop_turbo"
       ]
     },
     "build74-b1--device5": {
       "benchmarks": [
-        "blink_perf.dom",
         "blink_perf.layout",
-        "blink_perf.paint",
-        "dummy_benchmark.stable_benchmark_1",
-        "jetstream",
+        "dromaeo.domcoreattr",
+        "oortonline_tbmv2",
         "page_cycler_v2.intl_ar_fa_he",
         "power.android_acceptance",
-        "service_worker.service_worker_micro_benchmark",
         "smoothness.maps",
+        "smoothness.tough_webgl_cases",
         "thread_times.simple_mobile_sites"
       ]
     },
     "build74-b1--device6": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.css",
         "blink_perf.svg",
         "blob_storage.blob_storage",
-        "loading.cluster_telemetry",
         "media.android.tough_video_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.image_decoding_cases",
-        "smoothness.scrolling_tough_ad_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "thread_times.key_noop_cases",
         "thread_times.polymer",
         "v8.mobile_infinite_scroll-turbo_tbmv2",
@@ -149,78 +367,71 @@
     },
     "build74-b1--device7": {
       "benchmarks": [
-        "gpu_times.top_25_smooth",
-        "kraken",
-        "memory.long_running_idle_gmail_background_tbmv2",
-        "oortonline_tbmv2",
-        "power.top_25",
+        "image_decoding.image_decoding_measurement",
+        "media.mse_cases",
+        "memory.long_running_idle_gmail_tbmv2",
+        "smoothness.scrolling_tough_ad_cases",
         "speedometer-classic",
         "system_health.common_mobile",
-        "v8.google",
         "v8.infinite_scroll_tbmv2"
       ]
     },
     "build75-b1--device1": {
       "benchmarks": [
-        "image_decoding.image_decoding_measurement",
         "loading.mobile",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
-        "smoothness.tough_ad_cases",
-        "tracing.tracing_with_debug_overhead",
-        "v8.browsing_desktop",
-        "webrtc.datachannel"
+        "service_worker.service_worker",
+        "smoothness.tough_webgl_ad_cases",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
       ]
     },
     "build75-b1--device2": {
       "benchmarks": [
+        "blink_perf.events",
+        "dummy_benchmark.stable_benchmark_1",
         "power.trivial_pages",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_path_rendering_cases",
-        "smoothness.tough_webgl_cases",
-        "storage.indexeddb_endure_tracing"
+        "smoothness.tough_ad_cases",
+        "startup.large_profile.warm.blank_page"
       ]
     },
     "build75-b1--device3": {
       "benchmarks": [
-        "blink_perf.events",
-        "media.mse_cases",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_tbmv2",
+        "dromaeo.domcoremodify",
+        "media.media_cns_cases",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.key_desktop_move_cases",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
-        "thread_times.tough_scrolling_cases",
-        "v8.top_25_smooth"
+        "thread_times.tough_compositor_cases",
+        "thread_times.tough_scrolling_cases"
       ]
     },
     "build75-b1--device4": {
       "benchmarks": [
-        "blink_style.top_25",
+        "blink_perf.dom",
         "page_cycler_v2.basic_oopif",
-        "service_worker.service_worker",
+        "rasterize_and_record_micro.top_25",
         "smoothness.tough_canvas_cases",
         "speedometer-turbo",
         "start_with_ext.cold.blank_page",
+        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.key_silk_cases",
-        "v8.detached_context_age_in_gc",
-        "webrtc.webrtc_smoothness"
+        "thread_times.key_silk_cases"
       ]
     },
     "build75-b1--device5": {
       "benchmarks": [
-        "dromaeo.domcoremodify",
+        "blink_perf.css",
+        "blink_perf.parser",
         "page_cycler_v2.top_10_mobile",
         "rasterize_and_record_micro.key_silk_cases",
-        "rasterize_and_record_micro.top_25",
         "scheduler.tough_scheduling_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "smoothness.tough_image_decode_cases",
         "start_with_url.warm.startup_pages",
-        "startup.large_profile.warm.blank_page",
-        "startup.warm.blank_page",
-        "v8.key_mobile_sites_smooth",
         "v8.mobile_infinite_scroll-classic_tbmv2",
         "v8.mobile_infinite_scroll_tbmv2",
         "v8.runtimestats.browsing_desktop_turbo"
@@ -228,23 +439,714 @@
     },
     "build75-b1--device6": {
       "benchmarks": [
-        "dromaeo.domcoreattr",
+        "blink_perf.paint",
+        "kraken",
         "power.steady_state",
-        "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_texture_upload_cases",
-        "speedometer",
         "startup.cold.blank_page",
-        "webrtc.stress"
+        "tracing.tracing_with_background_memory_infra"
       ]
     },
     "build75-b1--device7": {
       "benchmarks": [
-        "blink_perf.parser",
+        "oortonline",
         "rasterize_and_record_micro.key_mobile_sites",
-        "smoothness.key_desktop_move_cases",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
+        "v8.runtime_stats.top_25",
+        "v8.runtimestats.browsing_desktop",
+        "v8.runtimestats.browsing_desktop_classic"
+      ]
+    }
+  },
+  "Android Nexus6 Perf": {
+    "build15-b1--device1": {
+      "benchmarks": [
+        "smoothness.key_silk_cases",
+        "system_health.memory_desktop",
+        "system_health.memory_mobile"
+      ]
+    },
+    "build15-b1--device2": {
+      "benchmarks": [
+        "loading.desktop",
+        "smoothness.simple_mobile_sites",
+        "v8.browsing_desktop_classic"
+      ]
+    },
+    "build15-b1--device3": {
+      "benchmarks": [
+        "page_cycler_v2.intl_ja_zh",
+        "v8.runtimestats.browsing_mobile_classic"
+      ]
+    },
+    "build15-b1--device4": {
+      "benchmarks": [
+        "blink_perf.blink_gc",
+        "page_cycler_v2.typical_25",
+        "v8.infinite_scroll-turbo_tbmv2"
+      ]
+    },
+    "build15-b1--device5": {
+      "benchmarks": [
+        "system_health.common_desktop",
+        "v8.browsing_mobile",
+        "v8.browsing_mobile_turbo"
+      ]
+    },
+    "build15-b1--device6": {
+      "benchmarks": [
+        "dromaeo.domcoretraverse",
+        "memory.desktop",
+        "power.typical_10_mobile",
+        "smoothness.tough_animation_cases",
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
+      ]
+    },
+    "build15-b1--device7": {
+      "benchmarks": [
+        "blink_perf.shadow_dom",
+        "dromaeo.domcorequery",
+        "memory.blink_memory_mobile",
+        "page_cycler_v2.intl_ko_th_vi",
+        "power.idle_platform",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "start_with_ext.warm.blank_page",
+        "v8.browsing_mobile_classic"
+      ]
+    },
+    "build16-b1--device1": {
+      "benchmarks": [
+        "battor.trivial_pages",
+        "media.tough_video_cases_tbmv2",
+        "octane",
+        "smoothness.gpu_rasterization.tough_scrolling_cases",
+        "smoothness.tough_filters_cases",
+        "thread_times.key_hit_test_cases",
+        "thread_times.key_idle_power_cases",
+        "tracing.tracing_with_debug_overhead",
+        "v8.infinite_scroll-classic_tbmv2",
+        "v8.runtimestats.browsing_mobile"
+      ]
+    },
+    "build16-b1--device2": {
+      "benchmarks": [
+        "dummy_benchmark.noisy_benchmark_1",
+        "jetstream",
+        "page_cycler_v2.intl_hi_ru",
+        "smoothness.tough_texture_upload_cases",
+        "speedometer"
+      ]
+    },
+    "build16-b1--device3": {
+      "benchmarks": [
+        "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.image_decoding_cases",
+        "smoothness.pathological_mobile_sites",
+        "smoothness.tough_pinch_zoom_cases",
+        "startup.large_profile.cold.blank_page",
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
+      ]
+    },
+    "build16-b1--device4": {
+      "benchmarks": [
+        "blink_perf.bindings",
+        "blink_perf.canvas",
+        "memory.dual_browser_test",
+        "page_cycler_v2.intl_es_fr_pt-BR",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.gpu_rasterization.polymer",
+        "start_with_url.cold.startup_pages",
+        "startup.warm.blank_page",
+        "startup.warm.chrome_signin",
+        "system_health.webview_startup",
+        "v8.browsing_desktop_turbo"
+      ]
+    },
+    "build16-b1--device5": {
+      "benchmarks": [
+        "blink_perf.layout",
+        "dromaeo.domcoreattr",
+        "oortonline_tbmv2",
+        "page_cycler_v2.intl_ar_fa_he",
+        "power.android_acceptance",
+        "smoothness.maps",
+        "smoothness.tough_webgl_cases",
+        "thread_times.simple_mobile_sites"
+      ]
+    },
+    "build16-b1--device6": {
+      "benchmarks": [
+        "battor.steady_state",
+        "blink_perf.svg",
+        "blob_storage.blob_storage",
+        "media.android.tough_video_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
+        "rasterize_and_record_micro.polymer",
+        "smoothness.gpu_rasterization.top_25_smooth",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
+        "thread_times.key_noop_cases",
+        "thread_times.polymer",
+        "v8.mobile_infinite_scroll-turbo_tbmv2",
+        "v8.runtimestats.browsing_mobile_turbo"
+      ]
+    },
+    "build16-b1--device7": {
+      "benchmarks": [
+        "image_decoding.image_decoding_measurement",
+        "media.mse_cases",
+        "memory.long_running_idle_gmail_tbmv2",
+        "smoothness.scrolling_tough_ad_cases",
+        "speedometer-classic",
+        "system_health.common_mobile",
+        "v8.infinite_scroll_tbmv2"
+      ]
+    },
+    "build45-b1--device1": {
+      "benchmarks": [
+        "loading.mobile",
+        "media.android.tough_video_cases_tbmv2",
+        "media.tough_video_cases",
+        "service_worker.service_worker",
+        "smoothness.tough_webgl_ad_cases",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
+      ]
+    },
+    "build45-b1--device2": {
+      "benchmarks": [
+        "blink_perf.events",
+        "dummy_benchmark.stable_benchmark_1",
+        "power.trivial_pages",
+        "smoothness.top_25_smooth",
+        "smoothness.tough_ad_cases",
+        "startup.large_profile.warm.blank_page"
+      ]
+    },
+    "build45-b1--device3": {
+      "benchmarks": [
+        "dromaeo.domcoremodify",
+        "media.media_cns_cases",
+        "memory.top_10_mobile_stress",
+        "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.key_desktop_move_cases",
+        "smoothness.sync_scroll.key_mobile_sites_smooth",
+        "thread_times.tough_compositor_cases",
+        "thread_times.tough_scrolling_cases"
+      ]
+    },
+    "build45-b1--device4": {
+      "benchmarks": [
+        "blink_perf.dom",
+        "page_cycler_v2.basic_oopif",
+        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_canvas_cases",
+        "speedometer-turbo",
+        "start_with_ext.cold.blank_page",
         "storage.indexeddb_endure",
+        "system_health.webview_startup_multiprocess",
+        "thread_times.key_silk_cases"
+      ]
+    },
+    "build45-b1--device5": {
+      "benchmarks": [
+        "blink_perf.css",
+        "blink_perf.parser",
+        "page_cycler_v2.top_10_mobile",
+        "rasterize_and_record_micro.key_silk_cases",
+        "scheduler.tough_scheduling_cases",
+        "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "smoothness.tough_image_decode_cases",
+        "start_with_url.warm.startup_pages",
+        "v8.mobile_infinite_scroll-classic_tbmv2",
+        "v8.mobile_infinite_scroll_tbmv2",
+        "v8.runtimestats.browsing_desktop_turbo"
+      ]
+    },
+    "build45-b1--device6": {
+      "benchmarks": [
+        "blink_perf.paint",
+        "kraken",
+        "power.steady_state",
+        "smoothness.key_mobile_sites_smooth",
+        "startup.cold.blank_page",
+        "tracing.tracing_with_background_memory_infra"
+      ]
+    },
+    "build45-b1--device7": {
+      "benchmarks": [
+        "oortonline",
+        "rasterize_and_record_micro.key_mobile_sites",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.tough_path_rendering_cases",
+        "smoothness.tough_scrolling_cases",
+        "v8.runtime_stats.top_25",
+        "v8.runtimestats.browsing_desktop",
+        "v8.runtimestats.browsing_desktop_classic"
+      ]
+    }
+  },
+  "Android Nexus7v2 Perf": {
+    "build10-b1--device1": {
+      "benchmarks": [
+        "battor.trivial_pages",
+        "media.tough_video_cases_tbmv2",
+        "octane",
+        "smoothness.gpu_rasterization.tough_scrolling_cases",
+        "smoothness.tough_filters_cases",
+        "thread_times.key_hit_test_cases",
+        "thread_times.key_idle_power_cases",
+        "tracing.tracing_with_debug_overhead",
+        "v8.infinite_scroll-classic_tbmv2",
+        "v8.runtimestats.browsing_mobile"
+      ]
+    },
+    "build10-b1--device2": {
+      "benchmarks": [
+        "dummy_benchmark.noisy_benchmark_1",
+        "jetstream",
+        "page_cycler_v2.intl_hi_ru",
+        "smoothness.tough_texture_upload_cases",
+        "speedometer"
+      ]
+    },
+    "build10-b1--device3": {
+      "benchmarks": [
+        "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.image_decoding_cases",
+        "smoothness.pathological_mobile_sites",
+        "smoothness.tough_pinch_zoom_cases",
+        "startup.large_profile.cold.blank_page",
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
+      ]
+    },
+    "build10-b1--device4": {
+      "benchmarks": [
+        "blink_perf.bindings",
+        "blink_perf.canvas",
+        "memory.dual_browser_test",
+        "page_cycler_v2.intl_es_fr_pt-BR",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.gpu_rasterization.polymer",
+        "start_with_url.cold.startup_pages",
+        "startup.warm.blank_page",
+        "startup.warm.chrome_signin",
+        "system_health.webview_startup",
+        "v8.browsing_desktop_turbo"
+      ]
+    },
+    "build10-b1--device5": {
+      "benchmarks": [
+        "blink_perf.layout",
+        "dromaeo.domcoreattr",
+        "oortonline_tbmv2",
+        "page_cycler_v2.intl_ar_fa_he",
+        "power.android_acceptance",
+        "smoothness.maps",
+        "smoothness.tough_webgl_cases",
+        "thread_times.simple_mobile_sites"
+      ]
+    },
+    "build10-b1--device6": {
+      "benchmarks": [
+        "battor.steady_state",
+        "blink_perf.svg",
+        "blob_storage.blob_storage",
+        "media.android.tough_video_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
+        "rasterize_and_record_micro.polymer",
+        "smoothness.gpu_rasterization.top_25_smooth",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
+        "thread_times.key_noop_cases",
+        "thread_times.polymer",
+        "v8.mobile_infinite_scroll-turbo_tbmv2",
+        "v8.runtimestats.browsing_mobile_turbo"
+      ]
+    },
+    "build10-b1--device7": {
+      "benchmarks": [
+        "image_decoding.image_decoding_measurement",
+        "media.mse_cases",
+        "memory.long_running_idle_gmail_tbmv2",
+        "smoothness.scrolling_tough_ad_cases",
+        "speedometer-classic",
+        "system_health.common_mobile",
+        "v8.infinite_scroll_tbmv2"
+      ]
+    },
+    "build49-b1--device1": {
+      "benchmarks": [
+        "loading.mobile",
+        "media.android.tough_video_cases_tbmv2",
+        "media.tough_video_cases",
+        "service_worker.service_worker",
+        "smoothness.tough_webgl_ad_cases",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
+      ]
+    },
+    "build49-b1--device2": {
+      "benchmarks": [
+        "blink_perf.events",
+        "dummy_benchmark.stable_benchmark_1",
+        "power.trivial_pages",
+        "smoothness.top_25_smooth",
+        "smoothness.tough_ad_cases",
+        "startup.large_profile.warm.blank_page"
+      ]
+    },
+    "build49-b1--device3": {
+      "benchmarks": [
+        "dromaeo.domcoremodify",
+        "media.media_cns_cases",
+        "memory.top_10_mobile_stress",
+        "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.key_desktop_move_cases",
+        "smoothness.sync_scroll.key_mobile_sites_smooth",
+        "thread_times.tough_compositor_cases",
+        "thread_times.tough_scrolling_cases"
+      ]
+    },
+    "build49-b1--device4": {
+      "benchmarks": [
+        "blink_perf.dom",
+        "page_cycler_v2.basic_oopif",
+        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_canvas_cases",
+        "speedometer-turbo",
+        "start_with_ext.cold.blank_page",
+        "storage.indexeddb_endure",
+        "system_health.webview_startup_multiprocess",
+        "thread_times.key_silk_cases"
+      ]
+    },
+    "build49-b1--device5": {
+      "benchmarks": [
+        "blink_perf.css",
+        "blink_perf.parser",
+        "page_cycler_v2.top_10_mobile",
+        "rasterize_and_record_micro.key_silk_cases",
+        "scheduler.tough_scheduling_cases",
+        "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "smoothness.tough_image_decode_cases",
+        "start_with_url.warm.startup_pages",
+        "v8.mobile_infinite_scroll-classic_tbmv2",
+        "v8.mobile_infinite_scroll_tbmv2",
+        "v8.runtimestats.browsing_desktop_turbo"
+      ]
+    },
+    "build49-b1--device6": {
+      "benchmarks": [
+        "blink_perf.paint",
+        "kraken",
+        "power.steady_state",
+        "smoothness.key_mobile_sites_smooth",
+        "startup.cold.blank_page",
+        "tracing.tracing_with_background_memory_infra"
+      ]
+    },
+    "build49-b1--device7": {
+      "benchmarks": [
+        "oortonline",
+        "rasterize_and_record_micro.key_mobile_sites",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.tough_path_rendering_cases",
+        "smoothness.tough_scrolling_cases",
+        "v8.runtime_stats.top_25",
+        "v8.runtimestats.browsing_desktop",
+        "v8.runtimestats.browsing_desktop_classic"
+      ]
+    },
+    "build9-b1--device1": {
+      "benchmarks": [
+        "smoothness.key_silk_cases",
+        "system_health.memory_desktop",
+        "system_health.memory_mobile"
+      ]
+    },
+    "build9-b1--device2": {
+      "benchmarks": [
+        "loading.desktop",
+        "smoothness.simple_mobile_sites",
+        "v8.browsing_desktop_classic"
+      ]
+    },
+    "build9-b1--device3": {
+      "benchmarks": [
+        "page_cycler_v2.intl_ja_zh",
+        "v8.runtimestats.browsing_mobile_classic"
+      ]
+    },
+    "build9-b1--device4": {
+      "benchmarks": [
+        "blink_perf.blink_gc",
+        "page_cycler_v2.typical_25",
+        "v8.infinite_scroll-turbo_tbmv2"
+      ]
+    },
+    "build9-b1--device5": {
+      "benchmarks": [
+        "system_health.common_desktop",
+        "v8.browsing_mobile",
+        "v8.browsing_mobile_turbo"
+      ]
+    },
+    "build9-b1--device6": {
+      "benchmarks": [
+        "dromaeo.domcoretraverse",
+        "memory.desktop",
+        "power.typical_10_mobile",
+        "smoothness.tough_animation_cases",
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
+      ]
+    },
+    "build9-b1--device7": {
+      "benchmarks": [
+        "blink_perf.shadow_dom",
+        "dromaeo.domcorequery",
+        "memory.blink_memory_mobile",
+        "page_cycler_v2.intl_ko_th_vi",
+        "power.idle_platform",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "start_with_ext.warm.blank_page",
+        "v8.browsing_mobile_classic"
+      ]
+    }
+  },
+  "Android One Perf": {
+    "build17-b1--device1": {
+      "benchmarks": [
+        "smoothness.key_silk_cases",
+        "system_health.memory_desktop",
+        "system_health.memory_mobile"
+      ]
+    },
+    "build17-b1--device2": {
+      "benchmarks": [
+        "loading.desktop",
+        "smoothness.simple_mobile_sites",
+        "v8.browsing_desktop_classic"
+      ]
+    },
+    "build17-b1--device3": {
+      "benchmarks": [
+        "page_cycler_v2.intl_ja_zh",
+        "v8.runtimestats.browsing_mobile_classic"
+      ]
+    },
+    "build17-b1--device4": {
+      "benchmarks": [
+        "blink_perf.blink_gc",
+        "page_cycler_v2.typical_25",
+        "v8.infinite_scroll-turbo_tbmv2"
+      ]
+    },
+    "build17-b1--device5": {
+      "benchmarks": [
+        "system_health.common_desktop",
+        "v8.browsing_mobile",
+        "v8.browsing_mobile_turbo"
+      ]
+    },
+    "build17-b1--device6": {
+      "benchmarks": [
+        "memory.desktop",
+        "power.typical_10_mobile",
+        "smoothness.tough_animation_cases",
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
+      ]
+    },
+    "build17-b1--device7": {
+      "benchmarks": [
+        "kraken",
+        "memory.blink_memory_mobile",
+        "page_cycler_v2.intl_ko_th_vi",
+        "power.idle_platform",
+        "start_with_ext.warm.blank_page",
+        "startup.warm.blank_page",
+        "v8.browsing_mobile_classic"
+      ]
+    },
+    "build18-b1--device1": {
+      "benchmarks": [
+        "battor.trivial_pages",
+        "dromaeo.domcoreattr",
+        "media.tough_video_cases_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
+        "oortonline_tbmv2",
+        "smoothness.gpu_rasterization.tough_scrolling_cases",
+        "thread_times.key_idle_power_cases",
+        "v8.infinite_scroll-classic_tbmv2",
+        "v8.runtimestats.browsing_mobile"
+      ]
+    },
+    "build18-b1--device2": {
+      "benchmarks": [
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoretraverse",
+        "memory.long_running_idle_gmail_background_tbmv2",
+        "page_cycler_v2.intl_hi_ru"
+      ]
+    },
+    "build18-b1--device3": {
+      "benchmarks": [
+        "dummy_benchmark.noisy_benchmark_1",
+        "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
+        "smoothness.pathological_mobile_sites",
+        "smoothness.tough_pinch_zoom_cases",
+        "startup.large_profile.cold.blank_page",
+        "startup.large_profile.warm.blank_page",
+        "tracing.tracing_with_debug_overhead"
+      ]
+    },
+    "build18-b1--device4": {
+      "benchmarks": [
+        "memory.dual_browser_test",
+        "page_cycler_v2.intl_es_fr_pt-BR",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.gpu_rasterization.polymer",
+        "smoothness.scrolling_tough_ad_cases",
+        "smoothness.tough_texture_upload_cases",
+        "start_with_url.cold.startup_pages",
+        "startup.warm.chrome_signin",
+        "storage.indexeddb_endure",
+        "system_health.webview_startup",
+        "v8.browsing_desktop_turbo"
+      ]
+    },
+    "build18-b1--device5": {
+      "benchmarks": [
+        "media.media_cns_cases",
+        "page_cycler_v2.intl_ar_fa_he",
+        "power.android_acceptance",
+        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.maps",
+        "smoothness.tough_path_rendering_cases",
+        "thread_times.simple_mobile_sites"
+      ]
+    },
+    "build18-b1--device6": {
+      "benchmarks": [
+        "battor.steady_state",
+        "blink_perf.layout",
+        "blink_perf.shadow_dom",
+        "media.android.tough_video_cases",
+        "octane",
+        "rasterize_and_record_micro.polymer",
+        "smoothness.gpu_rasterization.top_25_smooth",
+        "smoothness.tough_webgl_cases",
+        "thread_times.key_noop_cases",
+        "thread_times.polymer",
+        "v8.mobile_infinite_scroll-turbo_tbmv2",
+        "v8.runtimestats.browsing_mobile_turbo"
+      ]
+    },
+    "build18-b1--device7": {
+      "benchmarks": [
+        "blob_storage.blob_storage",
+        "jetstream",
+        "service_worker.service_worker",
+        "smoothness.image_decoding_cases",
+        "speedometer-classic",
+        "system_health.common_mobile",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
+      ]
+    },
+    "build47-b1--device1": {
+      "benchmarks": [
+        "blink_perf.css",
+        "dummy_benchmark.stable_benchmark_1",
+        "loading.mobile",
+        "media.android.tough_video_cases_tbmv2",
+        "power.trivial_pages",
+        "speedometer",
+        "thread_times.tough_compositor_cases",
+        "v8.infinite_scroll_tbmv2"
+      ]
+    },
+    "build47-b1--device2": {
+      "benchmarks": [
+        "blink_perf.canvas",
+        "media.tough_video_cases",
+        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_ad_cases",
+        "thread_times.tough_scrolling_cases"
+      ]
+    },
+    "build47-b1--device3": {
+      "benchmarks": [
+        "media.mse_cases",
+        "memory.top_10_mobile_stress",
+        "smoothness.key_desktop_move_cases",
+        "smoothness.sync_scroll.key_mobile_sites_smooth",
+        "smoothness.top_25_smooth",
+        "smoothness.tough_canvas_cases",
+        "smoothness.tough_filters_cases",
+        "storage.indexeddb_endure_tracing"
+      ]
+    },
+    "build47-b1--device4": {
+      "benchmarks": [
+        "blink_perf.bindings",
+        "dromaeo.domcorequery",
+        "page_cycler_v2.top_10_mobile",
+        "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "speedometer-turbo",
+        "start_with_ext.cold.blank_page",
+        "system_health.webview_startup_multiprocess",
+        "thread_times.key_silk_cases"
+      ]
+    },
+    "build47-b1--device5": {
+      "benchmarks": [
+        "blink_perf.parser",
+        "dromaeo.domcoremodify",
+        "oortonline",
+        "page_cycler_v2.basic_oopif",
+        "rasterize_and_record_micro.key_silk_cases",
+        "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "start_with_url.warm.startup_pages",
+        "startup.cold.blank_page",
+        "v8.detached_context_age_in_gc",
+        "v8.mobile_infinite_scroll-classic_tbmv2",
+        "v8.mobile_infinite_scroll_tbmv2",
+        "v8.runtimestats.browsing_desktop_turbo"
+      ]
+    },
+    "build47-b1--device6": {
+      "benchmarks": [
+        "blink_perf.events",
+        "blink_perf.svg",
+        "rasterize_and_record_micro.key_mobile_sites",
+        "scheduler.tough_scheduling_cases",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.key_mobile_sites_smooth"
+      ]
+    },
+    "build47-b1--device7": {
+      "benchmarks": [
+        "image_decoding.image_decoding_measurement",
+        "power.steady_state",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_scrolling_cases",
+        "thread_times.key_hit_test_cases",
         "tracing.tracing_with_background_memory_infra",
         "v8.runtime_stats.top_25",
         "v8.runtimestats.browsing_desktop",
@@ -270,7 +1172,6 @@
     "build245-m4--device3": {
       "benchmarks": [
         "page_cycler_v2.intl_ja_zh",
-        "power.typical_10_mobile_reload",
         "v8.runtimestats.browsing_mobile_classic"
       ]
     },
@@ -283,9 +1184,6 @@
     },
     "build245-m4--device5": {
       "benchmarks": [
-        "blink_style.key_mobile_sites",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "gpu_times.gpu_rasterization.top_25_smooth",
         "system_health.common_desktop",
         "v8.browsing_mobile",
         "v8.browsing_mobile_turbo"
@@ -293,107 +1191,98 @@
     },
     "build245-m4--device6": {
       "benchmarks": [
-        "blink_style.polymer",
         "dromaeo.domcoretraverse",
         "memory.desktop",
         "power.typical_10_mobile",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.tough_animation_cases",
-        "thread_times.key_mobile_sites_smooth"
+        "thread_times.key_mobile_sites_smooth",
+        "webrtc"
       ]
     },
     "build245-m4--device7": {
       "benchmarks": [
         "blink_perf.shadow_dom",
+        "dromaeo.domcorequery",
         "memory.blink_memory_mobile",
         "page_cycler_v2.intl_ko_th_vi",
         "power.idle_platform",
-        "smoothness.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "start_with_ext.warm.blank_page",
-        "thread_times.key_hit_test_cases",
-        "v8.browsing_mobile_classic",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.browsing_mobile_classic"
       ]
     },
     "build248-m4--device1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.canvas",
-        "dummy_benchmark.noisy_benchmark_1",
         "media.tough_video_cases_tbmv2",
+        "octane",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "smoothness.tough_filters_cases",
+        "thread_times.key_hit_test_cases",
         "thread_times.key_idle_power_cases",
+        "tracing.tracing_with_debug_overhead",
         "v8.infinite_scroll-classic_tbmv2",
-        "v8.runtimestats.browsing_mobile",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_mobile"
       ]
     },
     "build248-m4--device2": {
       "benchmarks": [
-        "oortonline",
+        "dummy_benchmark.noisy_benchmark_1",
+        "jetstream",
         "page_cycler_v2.intl_hi_ru",
-        "power.tough_ad_cases",
-        "rasterize_and_record_micro.partial_invalidation",
-        "smoothness.gpu_rasterization.tough_filters_cases",
-        "thread_times.tough_compositor_cases"
+        "smoothness.tough_texture_upload_cases",
+        "speedometer"
       ]
     },
     "build248-m4--device3": {
       "benchmarks": [
-        "blink_perf.bindings",
-        "dromaeo.domcorequery",
-        "media.media_cns_cases",
         "memory.top_10_mobile",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.pathological_mobile_sites",
         "smoothness.tough_pinch_zoom_cases",
         "startup.large_profile.cold.blank_page",
-        "sunspider"
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
       ]
     },
     "build248-m4--device4": {
       "benchmarks": [
-        "gpu_times.key_mobile_sites_smooth",
+        "blink_perf.bindings",
+        "blink_perf.canvas",
         "memory.dual_browser_test",
-        "octane",
         "page_cycler_v2.intl_es_fr_pt-BR",
-        "power.top_10",
+        "rasterize_and_record_micro.partial_invalidation",
         "smoothness.gpu_rasterization.polymer",
-        "smoothness.tough_image_decode_cases",
         "start_with_url.cold.startup_pages",
+        "startup.warm.blank_page",
         "startup.warm.chrome_signin",
         "system_health.webview_startup",
-        "tab_switching.typical_25",
         "v8.browsing_desktop_turbo"
       ]
     },
     "build248-m4--device5": {
       "benchmarks": [
-        "blink_perf.dom",
         "blink_perf.layout",
-        "blink_perf.paint",
-        "dummy_benchmark.stable_benchmark_1",
-        "jetstream",
+        "dromaeo.domcoreattr",
+        "oortonline_tbmv2",
         "page_cycler_v2.intl_ar_fa_he",
         "power.android_acceptance",
-        "service_worker.service_worker_micro_benchmark",
         "smoothness.maps",
+        "smoothness.tough_webgl_cases",
         "thread_times.simple_mobile_sites"
       ]
     },
     "build248-m4--device6": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.css",
         "blink_perf.svg",
         "blob_storage.blob_storage",
-        "loading.cluster_telemetry",
         "media.android.tough_video_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.image_decoding_cases",
-        "smoothness.scrolling_tough_ad_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "thread_times.key_noop_cases",
         "thread_times.polymer",
         "v8.mobile_infinite_scroll-turbo_tbmv2",
@@ -402,78 +1291,71 @@
     },
     "build248-m4--device7": {
       "benchmarks": [
-        "gpu_times.top_25_smooth",
-        "kraken",
-        "memory.long_running_idle_gmail_background_tbmv2",
-        "oortonline_tbmv2",
-        "power.top_25",
+        "image_decoding.image_decoding_measurement",
+        "media.mse_cases",
+        "memory.long_running_idle_gmail_tbmv2",
+        "smoothness.scrolling_tough_ad_cases",
         "speedometer-classic",
         "system_health.common_mobile",
-        "v8.google",
         "v8.infinite_scroll_tbmv2"
       ]
     },
     "build249-m4--device1": {
       "benchmarks": [
-        "image_decoding.image_decoding_measurement",
         "loading.mobile",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
-        "smoothness.tough_ad_cases",
-        "tracing.tracing_with_debug_overhead",
-        "v8.browsing_desktop",
-        "webrtc.datachannel"
+        "service_worker.service_worker",
+        "smoothness.tough_webgl_ad_cases",
+        "tab_switching.typical_25",
+        "v8.browsing_desktop"
       ]
     },
     "build249-m4--device2": {
       "benchmarks": [
+        "blink_perf.events",
+        "dummy_benchmark.stable_benchmark_1",
         "power.trivial_pages",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_path_rendering_cases",
-        "smoothness.tough_webgl_cases",
-        "storage.indexeddb_endure_tracing"
+        "smoothness.tough_ad_cases",
+        "startup.large_profile.warm.blank_page"
       ]
     },
     "build249-m4--device3": {
       "benchmarks": [
-        "blink_perf.events",
-        "media.mse_cases",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_tbmv2",
+        "dromaeo.domcoremodify",
+        "media.media_cns_cases",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
+        "smoothness.key_desktop_move_cases",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
-        "thread_times.tough_scrolling_cases",
-        "v8.top_25_smooth"
+        "thread_times.tough_compositor_cases",
+        "thread_times.tough_scrolling_cases"
       ]
     },
     "build249-m4--device4": {
       "benchmarks": [
-        "blink_style.top_25",
+        "blink_perf.dom",
         "page_cycler_v2.basic_oopif",
-        "service_worker.service_worker",
+        "rasterize_and_record_micro.top_25",
         "smoothness.tough_canvas_cases",
         "speedometer-turbo",
         "start_with_ext.cold.blank_page",
+        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.key_silk_cases",
-        "v8.detached_context_age_in_gc",
-        "webrtc.webrtc_smoothness"
+        "thread_times.key_silk_cases"
       ]
     },
     "build249-m4--device5": {
       "benchmarks": [
-        "dromaeo.domcoremodify",
+        "blink_perf.css",
+        "blink_perf.parser",
         "page_cycler_v2.top_10_mobile",
         "rasterize_and_record_micro.key_silk_cases",
-        "rasterize_and_record_micro.top_25",
         "scheduler.tough_scheduling_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
+        "smoothness.tough_image_decode_cases",
         "start_with_url.warm.startup_pages",
-        "startup.large_profile.warm.blank_page",
-        "startup.warm.blank_page",
-        "v8.key_mobile_sites_smooth",
         "v8.mobile_infinite_scroll-classic_tbmv2",
         "v8.mobile_infinite_scroll_tbmv2",
         "v8.runtimestats.browsing_desktop_turbo"
@@ -481,24 +1363,22 @@
     },
     "build249-m4--device6": {
       "benchmarks": [
-        "dromaeo.domcoreattr",
+        "blink_perf.paint",
+        "kraken",
         "power.steady_state",
-        "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_texture_upload_cases",
-        "speedometer",
         "startup.cold.blank_page",
-        "webrtc.stress"
+        "tracing.tracing_with_background_memory_infra"
       ]
     },
     "build249-m4--device7": {
       "benchmarks": [
-        "blink_perf.parser",
+        "oortonline",
         "rasterize_and_record_micro.key_mobile_sites",
-        "smoothness.key_desktop_move_cases",
+        "service_worker.service_worker_micro_benchmark",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "storage.indexeddb_endure",
-        "tracing.tracing_with_background_memory_infra",
         "v8.runtime_stats.top_25",
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_desktop_classic"
@@ -508,57 +1388,49 @@
   "Linux Perf": {
     "build148-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build149-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -573,110 +1445,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build150-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build151-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build152-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -687,67 +1548,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac 10.11 Perf": {
     "build102-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build103-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -762,110 +1612,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build104-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build105-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build106-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -876,67 +1715,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac 10.12 Perf": {
     "build158-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build159-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -951,110 +1779,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build160-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build161-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build162-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -1065,67 +1882,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac Air 10.11 Perf": {
     "build123-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build124-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -1140,110 +1946,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build125-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build126-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build127-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -1254,67 +2049,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac Mini 8GB 10.12 Perf": {
     "build24-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build25-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -1329,110 +2113,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build26-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build27-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build28-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -1443,67 +2216,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac Pro 10.11 Perf": {
     "build128-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build129-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -1518,110 +2280,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build130-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build131-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build132-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -1632,67 +2383,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Mac Retina Perf": {
     "build4-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build5-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -1707,110 +2447,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build6-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build7-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build8-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -1821,10 +2550,7 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
@@ -1847,8 +2573,6 @@
     },
     "build138-b1": {
       "benchmarks": [
-        "blink_style.polymer",
-        "loading.cluster_telemetry",
         "memory.dual_browser_test",
         "page_cycler_v2.intl_ja_zh",
         "smoothness.maps",
@@ -1877,7 +2601,6 @@
     },
     "build141-b1": {
       "benchmarks": [
-        "gpu_times.top_25_smooth",
         "power.idle_platform",
         "smoothness.tough_animation_cases",
         "smoothness.tough_pinch_zoom_cases",
@@ -1887,9 +2610,8 @@
     "build142-b1": {
       "benchmarks": [
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
+        "dromaeo.domcoremodify",
         "media.android.tough_video_cases",
-        "octane",
         "page_cycler_v2.intl_ko_th_vi",
         "smoothness.key_mobile_sites_smooth",
         "smoothness.key_silk_cases"
@@ -1898,59 +2620,50 @@
     "build143-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "dromaeo.domcorequery",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
-        "oortonline",
-        "service_worker.service_worker_micro_benchmark",
+        "media.media_cns_cases",
+        "service_worker.service_worker",
         "start_with_url.warm.startup_pages",
+        "thread_times.key_hit_test_cases",
         "thread_times.key_noop_cases"
       ]
     },
     "build144-b1": {
       "benchmarks": [
-        "blink_perf.canvas",
-        "blink_perf.events",
-        "dromaeo.domcoretraverse",
-        "jetstream",
+        "dromaeo.domcorequery",
+        "image_decoding.image_decoding_measurement",
+        "memory.long_running_idle_gmail_tbmv2",
         "page_cycler_v2.intl_hi_ru"
       ]
     },
     "build145-b1": {
       "benchmarks": [
-        "image_decoding.image_decoding_measurement",
-        "media.mse_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_image_decode_cases",
         "speedometer-classic",
         "startup.large_profile.cold.blank_page",
-        "v8.key_mobile_sites_smooth",
+        "tab_switching.typical_25",
         "v8.runtimestats.browsing_desktop_classic"
       ]
     },
     "build146-b1": {
       "benchmarks": [
-        "gpu_times.key_mobile_sites_smooth",
+        "jetstream",
         "page_cycler_v2.intl_es_fr_pt-BR",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "storage.indexeddb_endure",
-        "thread_times.key_hit_test_cases",
-        "thread_times.tough_compositor_cases",
-        "v8.runtimestats.browsing_desktop",
-        "webrtc.stress"
+        "tracing.tracing_with_background_memory_infra",
+        "v8.runtimestats.browsing_desktop"
       ]
     },
     "build147-b1": {
       "benchmarks": [
-        "dromaeo.domcoreattr",
+        "blink_perf.parser",
         "media.android.tough_video_cases_tbmv2",
-        "memory.long_running_idle_gmail_tbmv2",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_ar_fa_he",
-        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_path_rendering_cases",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_mobile",
         "v8.runtime_stats.top_25"
       ]
@@ -1958,11 +2671,11 @@
     "build148-b1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.svg",
-        "blink_style.top_25",
-        "rasterize_and_record_micro.partial_invalidation",
-        "startup.warm.blank_page",
-        "tracing.tracing_with_debug_overhead",
+        "blink_perf.paint",
+        "dummy_benchmark.noisy_benchmark_1",
+        "oortonline_tbmv2",
+        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_webgl_cases",
         "v8.mobile_infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_turbo"
       ]
@@ -1970,98 +2683,89 @@
     "build149-b1": {
       "benchmarks": [
         "blink_perf.layout",
-        "power.top_25",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
-        "smoothness.tough_path_rendering_cases",
+        "smoothness.scrolling_tough_ad_cases",
+        "smoothness.tough_texture_upload_cases",
         "start_with_ext.warm.blank_page",
-        "tracing.tracing_with_background_memory_infra",
-        "v8.google"
+        "startup.warm.blank_page",
+        "webrtc"
       ]
     },
     "build150-b1": {
       "benchmarks": [
         "blob_storage.blob_storage",
-        "kraken",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.tough_filters_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "dromaeo.domcoretraverse",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "storage.indexeddb_endure",
         "thread_times.simple_mobile_sites",
+        "tracing.tracing_with_debug_overhead",
         "v8.browsing_desktop"
       ]
     },
     "build151-b1": {
       "benchmarks": [
-        "blink_perf.dom",
-        "dromaeo.domcoremodify",
+        "kraken",
+        "octane",
+        "oortonline",
         "power.trivial_pages",
-        "smoothness.tough_image_decode_cases",
         "thread_times.key_idle_power_cases",
-        "v8.infinite_scroll_tbmv2",
-        "v8.top_25_smooth"
+        "thread_times.tough_compositor_cases",
+        "v8.infinite_scroll_tbmv2"
       ]
     },
     "build152-b1": {
       "benchmarks": [
-        "blink_perf.paint",
+        "blink_perf.events",
+        "blink_perf.svg",
         "media.tough_video_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.cold.blank_page",
-        "sunspider",
-        "tab_switching.typical_25",
         "thread_times.tough_scrolling_cases",
         "v8.browsing_mobile_classic"
       ]
     },
     "build153-b1": {
       "benchmarks": [
-        "blink_perf.bindings",
-        "dummy_benchmark.stable_benchmark_1",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
+        "blink_perf.dom",
         "power.android_acceptance",
-        "power.tough_ad_cases",
+        "service_worker.service_worker_micro_benchmark",
         "smoothness.top_25_smooth",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_texture_upload_cases",
-        "webrtc.peerconnection"
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
       ]
     },
     "build154-b1": {
       "benchmarks": [
-        "dummy_benchmark.noisy_benchmark_1",
-        "media.media_cns_cases",
+        "blink_perf.bindings",
+        "blink_perf.canvas",
+        "media.mse_cases",
         "page_cycler_v2.top_10_mobile",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.top_10",
-        "v8.detached_context_age_in_gc",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "v8.infinite_scroll-turbo_tbmv2"
       ]
     },
     "build155-b1": {
       "benchmarks": [
-        "blink_perf.parser",
-        "blink_style.key_mobile_sites",
-        "gpu_times.gpu_rasterization.top_25_smooth",
+        "blink_perf.shadow_dom",
         "memory.top_10_mobile",
         "page_cycler_v2.basic_oopif",
-        "power.typical_10_mobile_reload",
-        "speedometer",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.key_desktop_move_cases",
         "startup.cold.blank_page",
         "thread_times.key_silk_cases",
-        "v8.browsing_mobile",
-        "webrtc.datachannel",
-        "webrtc.webrtc_smoothness",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.browsing_mobile"
       ]
     },
     "build47-b4": {
       "benchmarks": [
         "blink_perf.css",
+        "dromaeo.domcoreattr",
         "media.tough_video_cases_tbmv2",
         "memory.top_10_mobile_stress",
         "rasterize_and_record_micro.key_mobile_sites",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.image_decoding_cases",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "thread_times.key_mobile_sites_smooth",
@@ -2071,74 +2775,66 @@
     },
     "build48-b4": {
       "benchmarks": [
+        "dummy_benchmark.stable_benchmark_1",
         "loading.mobile",
         "memory.desktop",
         "power.steady_state",
         "power.typical_10_mobile",
-        "smoothness.key_desktop_move_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_filters_cases",
         "smoothness.tough_scrolling_cases",
-        "startup.large_profile.warm.blank_page",
+        "speedometer",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure_tracing",
-        "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.getusermedia"
+        "v8.runtimestats.browsing_mobile_turbo"
       ]
     }
   },
   "Win 10 High-DPI Perf": {
     "build117-b1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build118-b1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -2153,110 +2849,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build119-b1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build120-b1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build180-b4": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -2267,10 +2952,7 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
@@ -2293,8 +2975,6 @@
     },
     "build202-b4": {
       "benchmarks": [
-        "blink_style.polymer",
-        "loading.cluster_telemetry",
         "memory.dual_browser_test",
         "page_cycler_v2.intl_ja_zh",
         "smoothness.maps",
@@ -2323,7 +3003,6 @@
     },
     "build205-b4": {
       "benchmarks": [
-        "gpu_times.top_25_smooth",
         "power.idle_platform",
         "smoothness.tough_animation_cases",
         "smoothness.tough_pinch_zoom_cases",
@@ -2333,9 +3012,8 @@
     "build206-b4": {
       "benchmarks": [
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
+        "dromaeo.domcoremodify",
         "media.android.tough_video_cases",
-        "octane",
         "page_cycler_v2.intl_ko_th_vi",
         "smoothness.key_mobile_sites_smooth",
         "smoothness.key_silk_cases"
@@ -2344,59 +3022,50 @@
     "build207-b4": {
       "benchmarks": [
         "battor.trivial_pages",
-        "dromaeo.domcorequery",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
-        "oortonline",
-        "service_worker.service_worker_micro_benchmark",
+        "media.media_cns_cases",
+        "service_worker.service_worker",
         "start_with_url.warm.startup_pages",
+        "thread_times.key_hit_test_cases",
         "thread_times.key_noop_cases"
       ]
     },
     "build208-b4": {
       "benchmarks": [
-        "blink_perf.canvas",
-        "blink_perf.events",
-        "dromaeo.domcoretraverse",
-        "jetstream",
+        "dromaeo.domcorequery",
+        "image_decoding.image_decoding_measurement",
+        "memory.long_running_idle_gmail_tbmv2",
         "page_cycler_v2.intl_hi_ru"
       ]
     },
     "build209-b4": {
       "benchmarks": [
-        "image_decoding.image_decoding_measurement",
-        "media.mse_cases",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_image_decode_cases",
         "speedometer-classic",
         "startup.large_profile.cold.blank_page",
-        "v8.key_mobile_sites_smooth",
+        "tab_switching.typical_25",
         "v8.runtimestats.browsing_desktop_classic"
       ]
     },
     "build210-b4": {
       "benchmarks": [
-        "gpu_times.key_mobile_sites_smooth",
+        "jetstream",
         "page_cycler_v2.intl_es_fr_pt-BR",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "storage.indexeddb_endure",
-        "thread_times.key_hit_test_cases",
-        "thread_times.tough_compositor_cases",
-        "v8.runtimestats.browsing_desktop",
-        "webrtc.stress"
+        "tracing.tracing_with_background_memory_infra",
+        "v8.runtimestats.browsing_desktop"
       ]
     },
     "build211-b4": {
       "benchmarks": [
-        "dromaeo.domcoreattr",
+        "blink_perf.parser",
         "media.android.tough_video_cases_tbmv2",
-        "memory.long_running_idle_gmail_tbmv2",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_ar_fa_he",
-        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_path_rendering_cases",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_mobile",
         "v8.runtime_stats.top_25"
       ]
@@ -2404,11 +3073,11 @@
     "build212-b4": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.svg",
-        "blink_style.top_25",
-        "rasterize_and_record_micro.partial_invalidation",
-        "startup.warm.blank_page",
-        "tracing.tracing_with_debug_overhead",
+        "blink_perf.paint",
+        "dummy_benchmark.noisy_benchmark_1",
+        "oortonline_tbmv2",
+        "rasterize_and_record_micro.top_25",
+        "smoothness.tough_webgl_cases",
         "v8.mobile_infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_turbo"
       ]
@@ -2416,98 +3085,89 @@
     "build213-b4": {
       "benchmarks": [
         "blink_perf.layout",
-        "power.top_25",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
-        "smoothness.tough_path_rendering_cases",
+        "smoothness.scrolling_tough_ad_cases",
+        "smoothness.tough_texture_upload_cases",
         "start_with_ext.warm.blank_page",
-        "tracing.tracing_with_background_memory_infra",
-        "v8.google"
+        "startup.warm.blank_page",
+        "webrtc"
       ]
     },
     "build214-b4": {
       "benchmarks": [
         "blob_storage.blob_storage",
-        "kraken",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.tough_filters_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "dromaeo.domcoretraverse",
+        "smoothness.gpu_rasterization.tough_filters_cases",
+        "storage.indexeddb_endure",
         "thread_times.simple_mobile_sites",
+        "tracing.tracing_with_debug_overhead",
         "v8.browsing_desktop"
       ]
     },
     "build215-b4": {
       "benchmarks": [
-        "blink_perf.dom",
-        "dromaeo.domcoremodify",
+        "kraken",
+        "octane",
+        "oortonline",
         "power.trivial_pages",
-        "smoothness.tough_image_decode_cases",
         "thread_times.key_idle_power_cases",
-        "v8.infinite_scroll_tbmv2",
-        "v8.top_25_smooth"
+        "thread_times.tough_compositor_cases",
+        "v8.infinite_scroll_tbmv2"
       ]
     },
     "build216-b4": {
       "benchmarks": [
-        "blink_perf.paint",
+        "blink_perf.events",
+        "blink_perf.svg",
         "media.tough_video_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.cold.blank_page",
-        "sunspider",
-        "tab_switching.typical_25",
         "thread_times.tough_scrolling_cases",
         "v8.browsing_mobile_classic"
       ]
     },
     "build217-b4": {
       "benchmarks": [
-        "blink_perf.bindings",
-        "dummy_benchmark.stable_benchmark_1",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
+        "blink_perf.dom",
         "power.android_acceptance",
-        "power.tough_ad_cases",
+        "service_worker.service_worker_micro_benchmark",
         "smoothness.top_25_smooth",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_texture_upload_cases",
-        "webrtc.peerconnection"
+        "storage.indexeddb_endure_tracing",
+        "v8.detached_context_age_in_gc"
       ]
     },
     "build218-b4": {
       "benchmarks": [
-        "dummy_benchmark.noisy_benchmark_1",
-        "media.media_cns_cases",
+        "blink_perf.bindings",
+        "blink_perf.canvas",
+        "media.mse_cases",
         "page_cycler_v2.top_10_mobile",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.top_10",
-        "v8.detached_context_age_in_gc",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "v8.infinite_scroll-turbo_tbmv2"
       ]
     },
     "build219-b4": {
       "benchmarks": [
-        "blink_perf.parser",
-        "blink_style.key_mobile_sites",
-        "gpu_times.gpu_rasterization.top_25_smooth",
+        "blink_perf.shadow_dom",
         "memory.top_10_mobile",
         "page_cycler_v2.basic_oopif",
-        "power.typical_10_mobile_reload",
-        "speedometer",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.key_desktop_move_cases",
         "startup.cold.blank_page",
         "thread_times.key_silk_cases",
-        "v8.browsing_mobile",
-        "webrtc.datachannel",
-        "webrtc.webrtc_smoothness",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.browsing_mobile"
       ]
     },
     "build220-b4": {
       "benchmarks": [
         "blink_perf.css",
+        "dromaeo.domcoreattr",
         "media.tough_video_cases_tbmv2",
         "memory.top_10_mobile_stress",
         "rasterize_and_record_micro.key_mobile_sites",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.image_decoding_cases",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "thread_times.key_mobile_sites_smooth",
@@ -2517,74 +3177,66 @@
     },
     "build221-b4": {
       "benchmarks": [
+        "dummy_benchmark.stable_benchmark_1",
         "loading.mobile",
         "memory.desktop",
         "power.steady_state",
         "power.typical_10_mobile",
-        "smoothness.key_desktop_move_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_filters_cases",
         "smoothness.tough_scrolling_cases",
-        "startup.large_profile.warm.blank_page",
+        "speedometer",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure_tracing",
-        "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.getusermedia"
+        "v8.runtimestats.browsing_mobile_turbo"
       ]
     }
   },
   "Win 10 Perf": {
     "build132-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build133-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -2599,110 +3251,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build134-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build135-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build136-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -2713,67 +3354,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 7 ATI GPU Perf": {
     "build101-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build102-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -2788,110 +3418,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build103-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build104-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build105-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -2902,67 +3521,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 7 Intel GPU Perf": {
     "build164-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build165-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -2977,110 +3585,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build166-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build167-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build168-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -3091,67 +3688,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 7 Nvidia GPU Perf": {
     "build92-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build93-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -3166,110 +3752,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build94-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build95-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build96-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -3280,67 +3855,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 7 Perf": {
     "build185-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build186-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -3355,110 +3919,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build187-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build188-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build189-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -3469,67 +4022,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 7 x64 Perf": {
     "build138-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build139-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -3544,110 +4086,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build140-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build141-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build142-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -3658,67 +4189,56 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
   "Win 8 Perf": {
     "build143-m1": {
       "benchmarks": [
-        "blink_perf.css",
-        "dromaeo.domcorequery",
-        "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-        "kraken",
+        "blink_perf.dom",
+        "blink_perf.paint",
+        "dromaeo.domcoremodify",
+        "dummy_benchmark.stable_benchmark_1",
         "media.android.tough_video_cases_tbmv2",
         "media.tough_video_cases",
         "memory.top_10_mobile",
+        "oortonline",
         "power.trivial_pages",
         "scheduler.tough_scheduling_cases",
-        "service_worker.service_worker",
-        "smoothness.desktop_tough_pinch_zoom_cases",
-        "smoothness.gpu_rasterization.tough_path_rendering_cases",
-        "smoothness.image_decoding_cases",
+        "smoothness.key_desktop_move_cases",
         "smoothness.key_mobile_sites_smooth",
-        "smoothness.tough_webgl_cases",
+        "smoothness.tough_ad_cases",
+        "smoothness.tough_image_decode_cases",
         "startup.cold.blank_page",
-        "storage.indexeddb_endure_tracing",
+        "startup.large_profile.warm.blank_page",
         "system_health.memory_desktop",
-        "tab_switching.typical_25",
         "thread_times.key_mobile_sites_smooth",
         "thread_times.key_silk_cases",
         "tracing.tracing_with_debug_overhead",
-        "v8.detached_context_age_in_gc",
-        "v8.runtime_stats.top_25",
-        "webrtc.webrtc_smoothness_tbmv2"
+        "v8.runtime_stats.top_25"
       ]
     },
     "build144-m1": {
       "benchmarks": [
         "blink_perf.bindings",
         "blink_perf.blink_gc",
-        "blink_perf.shadow_dom",
-        "blink_style.polymer",
+        "blink_perf.canvas",
         "dummy_benchmark.noisy_benchmark_1",
-        "gpu_times.top_25_smooth",
         "loading.desktop",
-        "memory.long_running_idle_gmail_tbmv2",
         "octane",
+        "oortonline_tbmv2",
         "page_cycler_v2.basic_oopif",
         "page_cycler_v2.intl_ar_fa_he",
         "power.idle_platform",
-        "power.top_10",
-        "power.tough_ad_cases",
         "rasterize_and_record_micro.key_silk_cases",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
-        "smoothness.scrolling_tough_ad_cases",
         "smoothness.top_25_smooth",
-        "smoothness.tough_image_decode_cases",
+        "smoothness.tough_webgl_cases",
         "startup.warm.blank_page",
-        "sunspider",
+        "storage.indexeddb_endure",
+        "storage.indexeddb_endure_tracing",
         "system_health.common_mobile",
         "system_health.memory_mobile",
         "thread_times.key_hit_test_cases",
@@ -3733,110 +4253,99 @@
         "v8.runtimestats.browsing_desktop",
         "v8.runtimestats.browsing_mobile_classic",
         "v8.runtimestats.browsing_mobile_turbo",
-        "webrtc.webrtc_smoothness"
+        "webrtc"
       ]
     },
     "build145-m1": {
       "benchmarks": [
         "battor.trivial_pages",
-        "blink_perf.dom",
-        "blink_perf.events",
         "blink_perf.layout",
-        "blink_perf.svg",
-        "blink_style.top_25",
         "dromaeo.domcoreattr",
-        "dummy_benchmark.stable_benchmark_1",
+        "image_decoding.image_decoding_measurement",
         "memory.dual_browser_test",
+        "memory.long_running_idle_gmail_background_tbmv2",
         "page_cycler_v2.intl_hi_ru",
         "page_cycler_v2.intl_ja_zh",
         "page_cycler_v2.top_10_mobile",
-        "power.top_25",
+        "rasterize_and_record_micro.top_25",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
-        "smoothness.gpu_rasterization.tough_filters_cases",
+        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
+        "smoothness.image_decoding_cases",
         "smoothness.simple_mobile_sites",
+        "smoothness.tough_filters_cases",
+        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_scrolling_cases",
-        "smoothness.tough_webgl_ad_cases",
+        "speedometer",
         "speedometer-turbo",
-        "startup.large_profile.warm.blank_page",
+        "tab_switching.typical_25",
+        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop_classic",
         "v8.browsing_desktop_turbo",
-        "v8.google",
         "v8.infinite_scroll-turbo_tbmv2",
         "v8.runtimestats.browsing_desktop_classic",
-        "v8.runtimestats.browsing_desktop_turbo",
-        "webrtc.datachannel",
-        "webrtc.getusermedia",
-        "webrtc.peerconnection"
+        "v8.runtimestats.browsing_desktop_turbo"
       ]
     },
     "build146-m1": {
       "benchmarks": [
-        "blink_perf.paint",
-        "blink_style.key_mobile_sites",
+        "blink_perf.parser",
+        "blink_perf.svg",
         "blob_storage.blob_storage",
-        "dromaeo.domcoremodify",
-        "gpu_times.gpu_rasterization.top_25_smooth",
-        "gpu_times.key_mobile_sites_smooth",
-        "loading.cluster_telemetry",
+        "dromaeo.domcorequery",
+        "dromaeo.domcoretraverse",
+        "jetstream",
         "media.android.tough_video_cases",
         "media.media_cns_cases",
         "memory.desktop",
-        "oortonline",
-        "oortonline_tbmv2",
         "page_cycler_v2.intl_es_fr_pt-BR",
         "page_cycler_v2.intl_ko_th_vi",
         "page_cycler_v2.typical_25",
         "power.android_acceptance",
         "power.steady_state",
         "power.typical_10_mobile",
-        "rasterize_and_record_micro.partial_invalidation",
         "rasterize_and_record_micro.polymer",
-        "rasterize_and_record_micro.top_25",
+        "service_worker.service_worker",
         "service_worker.service_worker_micro_benchmark",
+        "smoothness.gpu_rasterization.tough_filters_cases",
         "smoothness.gpu_rasterization.tough_pinch_zoom_cases",
-        "smoothness.key_desktop_move_cases",
-        "smoothness.tough_ad_cases",
+        "smoothness.scrolling_tough_ad_cases",
         "smoothness.tough_canvas_cases",
-        "smoothness.tough_filters_cases",
         "smoothness.tough_pinch_zoom_cases",
         "speedometer-classic",
         "start_with_ext.cold.blank_page",
         "start_with_url.cold.startup_pages",
         "startup.warm.chrome_signin",
-        "storage.indexeddb_endure",
         "system_health.webview_startup_multiprocess",
-        "thread_times.tough_compositor_cases",
         "v8.browsing_desktop",
+        "v8.detached_context_age_in_gc",
         "v8.mobile_infinite_scroll-classic_tbmv2"
       ]
     },
     "build147-m1": {
       "benchmarks": [
         "battor.steady_state",
-        "blink_perf.canvas",
-        "blink_perf.parser",
-        "dromaeo.domcoretraverse",
-        "image_decoding.image_decoding_measurement",
-        "jetstream",
+        "blink_perf.css",
+        "blink_perf.events",
+        "blink_perf.shadow_dom",
+        "kraken",
         "loading.mobile",
         "media.mse_cases",
         "media.tough_video_cases_tbmv2",
         "memory.blink_memory_mobile",
-        "memory.long_running_dual_browser_test",
-        "memory.long_running_idle_gmail_background_tbmv2",
+        "memory.long_running_idle_gmail_tbmv2",
         "memory.top_10_mobile_stress",
         "page_cycler_v2_site_isolation.basic_oopif",
-        "power.typical_10_mobile_reload",
         "rasterize_and_record_micro.key_mobile_sites",
+        "rasterize_and_record_micro.partial_invalidation",
+        "smoothness.desktop_tough_pinch_zoom_cases",
+        "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
-        "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
         "smoothness.maps",
         "smoothness.sync_scroll.key_mobile_sites_smooth",
         "smoothness.tough_animation_cases",
-        "smoothness.tough_path_rendering_cases",
         "smoothness.tough_texture_upload_cases",
-        "speedometer",
+        "smoothness.tough_webgl_ad_cases",
         "start_with_ext.warm.blank_page",
         "start_with_url.warm.startup_pages",
         "startup.large_profile.cold.blank_page",
@@ -3847,10 +4356,7 @@
         "v8.browsing_mobile_turbo",
         "v8.infinite_scroll-classic_tbmv2",
         "v8.infinite_scroll_tbmv2",
-        "v8.key_mobile_sites_smooth",
-        "v8.runtimestats.browsing_mobile",
-        "v8.top_25_smooth",
-        "webrtc.stress"
+        "v8.runtimestats.browsing_mobile"
       ]
     }
   },
@@ -3868,9 +4374,6 @@
     "blink_perf.parser",
     "blink_perf.shadow_dom",
     "blink_perf.svg",
-    "blink_style.key_mobile_sites",
-    "blink_style.polymer",
-    "blink_style.top_25",
     "blob_storage.blob_storage",
     "dromaeo.domcoreattr",
     "dromaeo.domcoremodify",
@@ -3878,14 +4381,9 @@
     "dromaeo.domcoretraverse",
     "dummy_benchmark.noisy_benchmark_1",
     "dummy_benchmark.stable_benchmark_1",
-    "gpu_times.gpu_rasterization.key_mobile_sites_smooth",
-    "gpu_times.gpu_rasterization.top_25_smooth",
-    "gpu_times.key_mobile_sites_smooth",
-    "gpu_times.top_25_smooth",
     "image_decoding.image_decoding_measurement",
     "jetstream",
     "kraken",
-    "loading.cluster_telemetry",
     "loading.desktop",
     "loading.mobile",
     "media.android.tough_video_cases",
@@ -3897,7 +4395,6 @@
     "memory.blink_memory_mobile",
     "memory.desktop",
     "memory.dual_browser_test",
-    "memory.long_running_dual_browser_test",
     "memory.long_running_idle_gmail_background_tbmv2",
     "memory.long_running_idle_gmail_tbmv2",
     "memory.top_10_mobile",
@@ -3917,12 +4414,8 @@
     "power.android_acceptance",
     "power.idle_platform",
     "power.steady_state",
-    "power.top_10",
-    "power.top_25",
-    "power.tough_ad_cases",
     "power.trivial_pages",
     "power.typical_10_mobile",
-    "power.typical_10_mobile_reload",
     "rasterize_and_record_micro.key_mobile_sites",
     "rasterize_and_record_micro.key_silk_cases",
     "rasterize_and_record_micro.partial_invalidation",
@@ -3974,7 +4467,6 @@
     "startup.warm.chrome_signin",
     "storage.indexeddb_endure",
     "storage.indexeddb_endure_tracing",
-    "sunspider",
     "system_health.common_desktop",
     "system_health.common_mobile",
     "system_health.memory_desktop",
@@ -4000,11 +4492,9 @@
     "v8.browsing_mobile_classic",
     "v8.browsing_mobile_turbo",
     "v8.detached_context_age_in_gc",
-    "v8.google",
     "v8.infinite_scroll-classic_tbmv2",
     "v8.infinite_scroll-turbo_tbmv2",
     "v8.infinite_scroll_tbmv2",
-    "v8.key_mobile_sites_smooth",
     "v8.mobile_infinite_scroll-classic_tbmv2",
     "v8.mobile_infinite_scroll-turbo_tbmv2",
     "v8.mobile_infinite_scroll_tbmv2",
@@ -4015,12 +4505,6 @@
     "v8.runtimestats.browsing_mobile",
     "v8.runtimestats.browsing_mobile_classic",
     "v8.runtimestats.browsing_mobile_turbo",
-    "v8.top_25_smooth",
-    "webrtc.datachannel",
-    "webrtc.getusermedia",
-    "webrtc.peerconnection",
-    "webrtc.stress",
-    "webrtc.webrtc_smoothness",
-    "webrtc.webrtc_smoothness_tbmv2"
+    "webrtc"
   ]
 }
\ No newline at end of file
diff --git a/tools/perf/core/desktop_benchmark_avg_times.json b/tools/perf/core/desktop_benchmark_avg_times.json
index 08092aca..d401d88 100644
--- a/tools/perf/core/desktop_benchmark_avg_times.json
+++ b/tools/perf/core/desktop_benchmark_avg_times.json
@@ -58,11 +58,7 @@
     "page_cycler_v2.tough_layout_cases": 1047.1903459546722,
     "page_cycler_v2.typical_25": 2253.314608139926,
     "page_cycler_v2_site_isolation.basic_oopif": 513.9117965158755,
-    "power.gpu_rasterization.top_10": 337.4231767654419,
-    "power.gpu_rasterization.top_25": 834.0499158447439,
     "power.steady_state": 596.0703444047408,
-    "power.top_10": 356.0645871018789,
-    "power.top_25": 813.9569391814146,
     "power.trivial_pages": 772.9753481583161,
     "rasterize_and_record_micro.key_mobile_sites": 625.6900956763161,
     "rasterize_and_record_micro.partial_invalidation": 15.75209499442059,
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index c663143..c2e4b0b 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -32,32 +32,6 @@
 SCRIPT_TESTS = [
   {
     'args': [
-      'gpu_perftests',
-      '--adb-path',
-      'src/third_party/catapult/devil/bin/deps/linux2/x86_64/bin/adb',
-    ],
-    'name': 'gpu_perftests',
-    'script': 'gtest_perf_test.py',
-    'testers': {
-      'chromium.perf': [
-        {
-          'name': 'Android Nexus5 Perf',
-          'shards': [2]
-        },
-        {
-          'name': 'Android Nexus7v2 Perf',
-          'shards': [2]
-        }
-        # crbug.com/663762
-        #{
-        #  'name': 'Android Nexus9 Perf',
-        #  'shards': [2]
-        #}
-      ],
-    }
-  },
-  {
-    'args': [
       'cc_perftests',
       '--adb-path',
       'src/third_party/catapult/devil/bin/deps/linux2/x86_64/bin/adb',
@@ -97,18 +71,6 @@
     'testers': {
       'chromium.perf': [
         {
-          'name': 'Android Nexus5 Perf',
-          'shards': [2]
-        },
-        {
-          'name': 'Android Nexus6 Perf',
-          'shards': [2]
-        },
-        {
-          'name': 'Android Nexus7v2 Perf',
-          'shards': [2]
-        },
-        {
           'name': 'Android Nexus9 Perf',
           'shards': [2]
         },
@@ -227,18 +189,6 @@
   # build/scripts/slave/recipe_modules/chromium_tests and must be kept in sync
   # to generate the correct json for each tester
   waterfall = add_tester(
-    waterfall, 'Android Nexus5 Perf', 'android-nexus5',
-    'android', target_bits=32, num_device_shards=7, num_host_shards=3)
-  waterfall = add_tester(
-    waterfall, 'Android Nexus5X Perf', 'android-nexus5X',
-    'android', target_bits=32, num_device_shards=7, num_host_shards=3)
-  waterfall = add_tester(
-    waterfall, 'Android Nexus6 Perf', 'android-nexus6',
-    'android', target_bits=32, num_device_shards=7, num_host_shards=3)
-  waterfall = add_tester(
-    waterfall, 'Android Nexus7v2 Perf', 'android-nexus7v2',
-   'android', target_bits=32, num_device_shards=7, num_host_shards=3)
-  waterfall = add_tester(
     waterfall, 'Android One Perf', 'android-one',
     'android', target_bits=32, num_device_shards=7, num_host_shards=3)
 
@@ -264,10 +214,114 @@
          ('tracing_perftests', 'build73-b1--device2'),
          ('gpu_perftests', 'build73-b1--device2'),
          #  ('cc_perftests', 'build73-b1--device2'),  # crbug.com/721757
-         ]
+        ]
       }
     ])
   waterfall = add_tester(
+    waterfall, 'Android Nexus5 Perf', 'android-nexus5', 'android',
+    swarming=[
+      {
+       'os': 'Android',
+       'android_devices': '1',
+       'pool': 'Chrome-perf',
+       'device_ids': [
+           'build13-b1--device1', 'build13-b1--device2', 'build13-b1--device3',
+           'build13-b1--device4', 'build13-b1--device5', 'build13-b1--device6',
+           'build13-b1--device7',
+           'build14-b1--device1', 'build14-b1--device2', 'build14-b1--device3',
+           'build14-b1--device4', 'build14-b1--device5', 'build14-b1--device6',
+           'build14-b1--device7',
+           'build48-b1--device1', 'build48-b1--device2', 'build48-b1--device3',
+           'build48-b1--device4', 'build48-b1--device5', 'build48-b1--device6',
+           'build48-b1--device7',
+          ],
+       'perf_tests': [
+         ('tracing_perftests', 'build13-b1--device2'),
+         ('gpu_perftests', 'build13-b1--device2'),
+         ('cc_perftests', 'build13-b1--device2'),
+        ]
+      }
+    ])
+
+  waterfall = add_tester(
+    waterfall, 'Android Nexus6 Perf', 'android-nexus6', 'android',
+    swarming=[
+      {
+       'os': 'Android',
+       'android_devices': '1',
+       'pool': 'Chrome-perf',
+       'device_ids': [
+           'build15-b1--device1', 'build15-b1--device2', 'build15-b1--device3',
+           'build15-b1--device4', 'build15-b1--device5', 'build15-b1--device6',
+           'build15-b1--device7',
+           'build16-b1--device1', 'build16-b1--device2', 'build16-b1--device3',
+           'build16-b1--device4', 'build16-b1--device5', 'build16-b1--device6',
+           'build16-b1--device7',
+           'build45-b1--device1', 'build45-b1--device2', 'build45-b1--device3',
+           'build45-b1--device4', 'build45-b1--device5', 'build45-b1--device6',
+           'build45-b1--device7',
+          ],
+       'perf_tests': [
+         ('tracing_perftests', 'build15-b1--device2'),
+         ('gpu_perftests', 'build16-b1--device2'),
+         ('cc_perftests', 'build45-b1--device2'),
+        ]
+      }
+    ])
+
+  waterfall = add_tester(
+    waterfall, 'Android Nexus7v2 Perf', 'android-nexus7v2', 'android',
+    swarming=[
+      {
+       'os': 'Android',
+       'android_devices': '1',
+       'pool': 'Chrome-perf',
+       'device_ids': [
+           'build9-b1--device1', 'build9-b1--device2', 'build9-b1--device3',
+           'build9-b1--device4', 'build9-b1--device5', 'build9-b1--device6',
+           'build9-b1--device7',
+           'build10-b1--device1', 'build10-b1--device2', 'build10-b1--device3',
+           'build10-b1--device4', 'build10-b1--device5', 'build10-b1--device6',
+           'build10-b1--device7',
+           'build49-b1--device1', 'build49-b1--device2', 'build49-b1--device3',
+           'build49-b1--device4', 'build49-b1--device5', 'build49-b1--device6',
+           'build49-b1--device7',
+          ],
+       'perf_tests': [
+         ('tracing_perftests', 'build9-b1--device2'),
+         ('gpu_perftests', 'build10-b1--device2'),
+         ('cc_perftests', 'build49-b1--device2'),
+        ]
+      }
+    ])
+
+  waterfall = add_tester(
+    waterfall, 'Android One Perf', 'android-nexus7v2', 'android',
+    swarming=[
+      {
+       'os': 'Android',
+       'android_devices': '1',
+       'pool': 'Chrome-perf',
+       'device_ids': [
+           'build17-b1--device1', 'build17-b1--device2', 'build17-b1--device3',
+           'build17-b1--device4', 'build17-b1--device5', 'build17-b1--device6',
+           'build17-b1--device7',
+           'build18-b1--device1', 'build18-b1--device2', 'build18-b1--device3',
+           'build18-b1--device4', 'build18-b1--device5', 'build18-b1--device6',
+           'build18-b1--device7',
+           'build47-b1--device1', 'build47-b1--device2', 'build47-b1--device3',
+           'build47-b1--device4', 'build47-b1--device5', 'build47-b1--device6',
+           'build47-b1--device7',
+          ],
+       'perf_tests': [
+         ('tracing_perftests', 'build17-b1--device2'),
+         ('gpu_perftests', 'build18-b1--device2'),
+         ('cc_perftests', 'build47-b1--device2'),
+        ]
+      }
+    ])
+
+  waterfall = add_tester(
     waterfall, 'Win 10 High-DPI Perf', 'win-high-dpi', 'win',
     swarming=[
       {
@@ -700,7 +754,7 @@
 
 # Overrides the default 2 hour timeout for swarming tasks.
 BENCHMARK_SWARMING_TIMEOUTS = {
-    'loading.mobile': 14400, # 4 hours
+    'loading.mobile': 16200, # 4.5 hours
     'system_health.memory_mobile': 10800, # 4 hours
 }
 
diff --git a/tools/perf/core/sharding_map_generator.py b/tools/perf/core/sharding_map_generator.py
index e5e2f18..f487a52d 100644
--- a/tools/perf/core/sharding_map_generator.py
+++ b/tools/perf/core/sharding_map_generator.py
@@ -109,18 +109,22 @@
   return benchmark_to_shard_dict
 
 
-def regenerate(benchmarks, waterfall_configs):
+def regenerate(benchmarks, waterfall_configs, buildernames=None):
   """Regenerate the shard mapping file.
 
   This overwrites the current file with fresh data.
   """
-  sharding_map = {
-      'all_benchmarks': [b.Name() for b in benchmarks],
-  }
+  with open(get_sharding_map_path()) as f:
+    sharding_map = json.load(f)
+  sharding_map[u'all_benchmarks'] = [b.Name() for b in benchmarks]
+
   for name, config in waterfall_configs.items():
     for buildername, tester in config['testers'].items():
       if not tester.get('swarming'):
         continue
+
+      if buildernames and buildername not in buildernames:
+        continue
       per_builder = {}
 
       devices = tester['swarming_dimensions'][0]['device_ids']
@@ -134,6 +138,7 @@
         per_builder[device] = device_map
       sharding_map[buildername] = per_builder
 
+
   for name, builder_values in sharding_map.items():
     if name == 'all_benchmarks':
       builder_values.sort()
@@ -155,9 +160,10 @@
                    'benchmarks in tools/perf/benchmarks.'))
 
   parser.add_argument('mode', choices=['regenerate'])
+  parser.add_argument('--buildernames', '-b', action='append', default=None)
   return parser
 
 
 def main(args, benchmarks, configs):
   if args.mode == 'regenerate':
-    return regenerate(benchmarks, configs)
+    return regenerate(benchmarks, configs, args.buildernames)
diff --git a/tools/perf/docs/apk_size_regressions.md b/tools/perf/docs/apk_size_regressions.md
index 8e60f241..a39a748a 100644
--- a/tools/perf/docs/apk_size_regressions.md
+++ b/tools/perf/docs/apk_size_regressions.md
@@ -61,17 +61,14 @@
  * File a bug (TODO:
 [Make this template automatic](https://github.com/catapult-project/catapult/issues/3150)).
     * Change the bug's title from `X%` to `XXkb`
-    * Remove label: `Restrict-View-Google`
     * Assign to commit author
     * Set description to (replacing **bold** parts):
-      > Alert caused by "**First line of commit message**"
-      >
+      > Caused by "**First line of commit message**"
       > Commit: **abc123abc123abc123abc123abc123abc123abcd**
       >
       > Link to size graph:
 [https://chromeperf.appspot.com/report?sid=a097e74b1aa288511afb4cb616efe0f95ba4d347ad61d5e835072f23450938ba&rev=**440074**](https://chromeperf.appspot.com/report?sid=cfc29eed1238fd38fb5e6cf83bdba6c619be621b606e03e5dfc2e99db14c418b&rev=440074)
       >
-      >
       > How to debug this size regressions is documented at:
 https://chromium.googlesource.com/chromium/src/+/master/tools/perf/docs/apk_size_regressions.md#Debugging-Apk-Size-Increase
 
@@ -102,10 +99,13 @@
 
  * Use [//tools/binary_size/diagnose_bloat.py](https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/README.md)
 to show a diff of ELF symbols.
+   * Googlers should use the speedy `--cloud` option. E.g.:
+   * `tools/binary_size/diagnose_bloat.py 0f30c9488bd2bdc1db2749cd4683994a764a44c9 --cloud`
  * Paste the diff into the bug.
  * If the diff looks reasonable, close as `Won't Fix`.
  * Otherwise, try to refactor a bit (e.g.
  [move code out of templates](https://bugs.chromium.org/p/chromium/issues/detail?id=716393)).
+ * If symbols are larger than expected, use the `Disassemble()` feature of `supersize console` to see what is going on.
 
 ### Growth is from Java code
 
diff --git a/tools/perf/generate_system_health_csv b/tools/perf/generate_system_health_csv
new file mode 100755
index 0000000..aa1c079
--- /dev/null
+++ b/tools/perf/generate_system_health_csv
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import csv
+import os
+import sys
+
+from core import path_util
+sys.path.insert(1, path_util.GetTelemetryDir())  # To resolve telemetry imports
+
+import page_sets
+
+
+def IterAllSystemHealthStories():
+  for s in page_sets.SystemHealthStorySet(platform='desktop'):
+    yield s
+  for s in page_sets.SystemHealthStorySet(platform='mobile'):
+    if len(s.SUPPORTED_PLATFORMS) < 2:
+      yield s
+
+SYSTEM_HEALTH_CSV = os.path.join(os.path.dirname(__file__),
+                                 'system_health_stories.csv')
+
+
+def main():
+  system_health_stories = list(IterAllSystemHealthStories())
+  system_health_stories.sort(key=lambda s: s.name)
+  with open(SYSTEM_HEALTH_CSV, 'w') as f:
+    csv_writer = csv.writer(f)
+    csv_writer.writerow([
+        'Story name', 'Platform', 'Description'])
+    for s in system_health_stories:
+      p = s.SUPPORTED_PLATFORMS
+      if len(p) == 2:
+        p = 'all'
+      else:
+        p = list(p)[0]
+      csv_writer.writerow([s.name, p, s.GetStoryDescription()])
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/perf/list_system_health_stories b/tools/perf/list_system_health_stories
deleted file mode 100755
index cfc494a..0000000
--- a/tools/perf/list_system_health_stories
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import sys
-
-from core import path_util
-sys.path.insert(1, path_util.GetTelemetryDir())  # To resolve telemetry imports
-
-import page_sets
-
-
-def IterAllSystemHealthStories():
-  for s in page_sets.SystemHealthStorySet(platform='desktop'):
-    yield s
-  for s in page_sets.SystemHealthStorySet(platform='mobile'):
-    if len(s.SUPPORTED_PLATFORMS) < 2:
-      yield s
-
-
-def main():
-  system_health_stories = list(IterAllSystemHealthStories())
-  system_health_stories.sort(key=lambda s: s.name)
-  print '{0:60} {1}'.format('Story name', 'Supported platform')
-  print '-' * 79
-  for s in system_health_stories:
-    p = s.SUPPORTED_PLATFORMS
-    if len(p) == 2:
-      p = 'all'
-    else:
-      p = list(p)[0]
-    print '{0:60} {1}'.format(s.name, p)
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/tools/perf/measurements/blink_style.py b/tools/perf/measurements/blink_style.py
deleted file mode 100644
index dae97c7..0000000
--- a/tools/perf/measurements/blink_style.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from collections import defaultdict
-from itertools import starmap
-from telemetry.core import util
-from telemetry.page import legacy_page_test
-from telemetry.value import scalar
-
-from measurements import timeline_controller
-import py_utils
-
-
-class BlinkStyle(legacy_page_test.LegacyPageTest):
-
-  def __init__(self):
-    super(BlinkStyle, self).__init__()
-    self._controller = None
-
-  def WillNavigateToPage(self, page, tab):
-    self._controller = timeline_controller.TimelineController()
-    self._controller.trace_categories = 'blink_style,blink.console'
-    self._controller.SetUp(page, tab)
-    self._controller.Start(tab)
-
-  def DidRunPage(self, platform):
-    if self._controller:
-      self._controller.CleanUp(platform)
-
-  def ValidateAndMeasurePage(self, page, tab, results):
-    with tab.action_runner.CreateInteraction('wait-for-quiescence'):
-      tab.ExecuteJavaScript('console.time("");')
-      try:
-        util.WaitFor(tab.HasReachedQuiescence, 15)
-      except py_utils.TimeoutException:
-        # Some sites never reach quiesence. As this benchmark normalizes/
-        # categories results, it shouldn't be necessary to reach the same
-        # state on every run.
-        pass
-
-    tab.ExecuteJavaScript('''
-        for (var i = 0; i < 11; i++) {
-          var cold = i % 2 == 0;
-          var name = "update_style";
-          if (cold) name += "_cold";
-          console.time(name);
-          // Occasionally documents will break the APIs we need
-          try {
-            // On cold runs, force a new StyleResolver
-            if (cold) {
-              var style = document.createElement("style");
-              document.head.appendChild(style);
-              style.remove();
-            }
-            // Invalidate style for the whole document
-            document.documentElement.lang += "z";
-            // Force a style update (but not layout)
-            getComputedStyle(document.documentElement).color;
-          } catch (e) {}
-          console.timeEnd(name);
-        }''')
-
-    self._controller.Stop(tab, results)
-    renderer = self._controller.model.GetRendererThreadFromTabId(tab.id)
-    markers = [event for event in renderer.async_slices
-               if event.name.startswith('update_style')
-               and event.category == 'blink.console']
-    # Drop the first run.
-    markers = markers[1:]
-    assert len(markers) == 10
-
-    def duration(event):
-      if event.has_thread_timestamps:
-        return event.thread_duration
-      else:
-        return event.duration
-
-    for marker in markers:
-      for event in renderer.all_slices:
-        if (event.name == 'Document::updateStyle'
-            and event.start >= marker.start
-            and event.end <= marker.end):
-          access_count = event.args.get('resolverAccessCount')
-          if access_count is None:
-            # absent in earlier versions
-            continue
-          min_access_count = 50
-
-          if access_count >= min_access_count:
-            result = 1000 * (duration(event) / access_count)
-            results.AddValue(scalar.ScalarValue(
-                page, marker.name, 'ms/1000 elements', result))
-
-    class ParserEvent(object):
-
-      def __init__(self, summary_event, tokenize_event, parse_event):
-        min_sheet_length = 1000
-        ua_sheet_mode = 5
-        enormous_token_threshold = 100
-        large_token_threshold = 5
-
-        self.mode = summary_event.args.get('mode')
-        self.length = summary_event.args.get('length')
-        self.tokens = summary_event.args.get('tokenCount')
-        self.tokenize_duration = duration(tokenize_event)
-        self.parse_duration = duration(parse_event)
-        self.chars_per_token = 0
-        if self.tokens:
-          self.chars_per_token = self.length / float(self.tokens)
-        if self.mode == ua_sheet_mode or self.length < min_sheet_length:
-          self.category = 'ignored'
-        elif self.chars_per_token > enormous_token_threshold:
-          self.category = 'enormous_tokens'
-        elif self.chars_per_token > large_token_threshold:
-          self.category = 'large_tokens'
-        else:
-          self.category = 'regular'
-
-    parser_events = [event for event in renderer.all_slices
-                     if event.name == 'CSSParserImpl::parseStyleSheet'
-                     or event.name == 'CSSParserImpl::parseStyleSheet.tokenize'
-                     or event.name == 'CSSParserImpl::parseStyleSheet.parse']
-
-    merged_events = starmap(ParserEvent, zip(*[iter(parser_events)] * 3))
-
-    events_by_category = defaultdict(list)
-    for event in merged_events:
-      if event.category != 'ignored':
-        events_by_category[event.category].append(event)
-
-    for category, events in events_by_category.items():
-      parse_duration = sum(event.parse_duration for event in events)
-      tokenize_duration = sum(event.tokenize_duration for event in events)
-      tokens = sum(event.tokens for event in events)
-      length = sum(event.length for event in events)
-
-      results.AddValue(
-          scalar.ScalarValue(page, ('parse_css_%s' % category),
-                             'tokens/s', 1000 / (parse_duration / tokens)))
-
-      results.AddValue(
-          scalar.ScalarValue(page, ('tokenize_css_%s' % category),
-                             'char/s',  1000 / (tokenize_duration / length)))
diff --git a/tools/perf/measurements/blink_style_unittest.py b/tools/perf/measurements/blink_style_unittest.py
deleted file mode 100644
index b9c246a..0000000
--- a/tools/perf/measurements/blink_style_unittest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from measurements import blink_style
-
-from telemetry import decorators
-from telemetry.testing import options_for_unittests
-from telemetry.testing import page_test_test_case
-
-
-class BlinkStyleTest(page_test_test_case.PageTestTestCase):
-  """Smoke test for Bink Style measurements.
-
-     Runs BlinkStyle measurement on some simple pages and verifies
-     that expected metrics were added to the results.  The test is purely
-     functional, i.e. it only checks if the metrics are present and non-zero.
-  """
-
-  def setUp(self):
-    self._options = options_for_unittests.GetCopy()
-
-  @decorators.Disabled('chromeos')  # crbug.com/483212
-  def testForParsing(self):
-    ps = self.CreateStorySetFromFileInUnittestDataDir('blink_style.html')
-    measurement = blink_style.BlinkStyle()
-    results = self.RunMeasurement(measurement, ps, options=self._options)
-    self.assertEquals(0, len(results.failures))
-
-    def getMetric(results, name, count=1):
-      metrics = results.FindAllPageSpecificValuesNamed(name)
-      self.assertEquals(count, len(metrics))
-      return metrics[0].value
-
-    self.assertGreater(getMetric(results, 'parse_css_regular'), 0)
-    self.assertGreater(getMetric(results, 'tokenize_css_regular'), 0)
-    self.assertGreater(getMetric(results, 'update_style', 5), 0)
-    self.assertGreater(getMetric(results, 'update_style_cold', 5), 0)
diff --git a/tools/perf/measurements/webrtc.py b/tools/perf/measurements/webrtc.py
deleted file mode 100644
index c2e399b..0000000
--- a/tools/perf/measurements/webrtc.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from telemetry.page import legacy_page_test
-
-from metrics import cpu
-from metrics import media
-from metrics import power
-from metrics import webrtc_stats
-
-
-class WebRTC(legacy_page_test.LegacyPageTest):
-  """Gathers WebRTC-related metrics on a page set."""
-
-  def __init__(self, particular_metrics=None):
-    """Create the measurement and include selected stats.
-
-    Args:
-        particular_metrics: A list of the stats to include (see webrtc_stats.py
-            for a list of valid names) or None to select all metrics.
-    """
-    super(WebRTC, self).__init__()
-    self._cpu_metric = None
-    self._media_metric = None
-    self._power_metric = None
-    self._particular_metrics = particular_metrics
-    self._webrtc_stats_metric = None
-
-  def WillStartBrowser(self, platform):
-    self._power_metric = power.PowerMetric(platform)
-
-  def DidStartBrowser(self, browser):
-    self._cpu_metric = cpu.CpuMetric(browser)
-    self._webrtc_stats_metric = webrtc_stats.WebRtcStatisticsMetric(
-        self._particular_metrics)
-
-  def DidNavigateToPage(self, page, tab):
-    self._cpu_metric.Start(page, tab)
-    self._media_metric = media.MediaMetric(tab)
-    self._media_metric.Start(page, tab)
-    self._power_metric.Start(page, tab)
-    self._webrtc_stats_metric.Start(page, tab)
-
-  def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArgs('--use-fake-device-for-media-stream')
-    options.AppendExtraBrowserArgs('--use-fake-ui-for-media-stream')
-    power.PowerMetric.CustomizeBrowserOptions(options)
-
-  def ValidateAndMeasurePage(self, page, tab, results):
-    """Measure the page's performance."""
-    self._cpu_metric.Stop(page, tab)
-    self._cpu_metric.AddResults(tab, results)
-
-    # Add all media metrics except bytes (those aren't hooked up for WebRTC
-    # video tags).
-    exclude_metrics = ['decoded_video_bytes', 'decoded_audio_bytes']
-    self._media_metric.Stop(page, tab)
-    self._media_metric.AddResults(tab, results, exclude_metrics=exclude_metrics)
-
-    self._power_metric.Stop(page, tab)
-    self._power_metric.AddResults(tab, results)
-
-    self._webrtc_stats_metric.Stop(page, tab)
-    self._webrtc_stats_metric.AddResults(tab, results)
-
-  def DidRunPage(self, platform):
-    del platform  # unused
-    self._power_metric.Close()
diff --git a/tools/perf/page_sets/__init__.py b/tools/perf/page_sets/__init__.py
index 5a11235..e6a166f 100644
--- a/tools/perf/page_sets/__init__.py
+++ b/tools/perf/page_sets/__init__.py
@@ -8,13 +8,15 @@
 
 from telemetry.core import discover
 from telemetry import story
+from telemetry.story import expectations
 
 
 # Import all submodules' PageSet classes.
 start_dir = os.path.dirname(os.path.abspath(__file__))
 top_level_dir = os.path.dirname(start_dir)
-base_class = story.StorySet
+base_classes = [story.StorySet, expectations.StoryExpectations]
 
-for cls in discover.DiscoverClasses(
-    start_dir, top_level_dir, base_class).values():
-  setattr(sys.modules[__name__], cls.__name__, cls)
+for base_class in base_classes:
+  for cls in discover.DiscoverClasses(
+      start_dir, top_level_dir, base_class).values():
+    setattr(sys.modules[__name__], cls.__name__, cls)
diff --git a/tools/perf/page_sets/data/v8_pages.json b/tools/perf/page_sets/data/v8_pages.json
deleted file mode 100644
index 45f77c9..0000000
--- a/tools/perf/page_sets/data/v8_pages.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "archives": {
-        "AdwordsCampaign": {
-            "DEFAULT": "v8_pages_000.wpr"
-        }
-    },
-    "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
-    "platform_specific": true
-}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/v8_pages_000.wpr.sha1 b/tools/perf/page_sets/data/v8_pages_000.wpr.sha1
deleted file mode 100644
index 5734d96..0000000
--- a/tools/perf/page_sets/data/v8_pages_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c07fd5bed1f3cb38d6607b5760caa3846e08becb
\ No newline at end of file
diff --git a/tools/perf/page_sets/google_pages.py b/tools/perf/page_sets/google_pages.py
index abdb76a..6fb0ef4 100644
--- a/tools/perf/page_sets/google_pages.py
+++ b/tools/perf/page_sets/google_pages.py
@@ -6,7 +6,6 @@
 
 from telemetry.page import page as page_module
 from telemetry.page import shared_page_state
-from telemetry.util import js_template
 
 import os
 
@@ -58,25 +57,3 @@
     action_runner.Wait(2)
     action_runner.WaitForJavaScriptCondition(
         'document.getElementsByClassName("kix-appview-editor").length')
-
-
-INTERACTION_NAME = 'Interaction.AppLoad'
-class AdwordCampaignDesktopPage(page_module.Page):
-  def __init__(self, page_set):
-    super(AdwordCampaignDesktopPage, self).__init__(
-        url='https://adwords.google.com/cm/CampaignMgmt',
-        page_set=page_set, name='AdwordsCampaign',
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.script_to_evaluate_on_commit = js_template.Render(
-        'console.time({{ label }});', label=INTERACTION_NAME)
-
-  def RunNavigateSteps(self, action_runner):
-    google_login.LoginGoogleAccount(action_runner, 'google3',
-                                    self.credentials_path)
-    super(AdwordCampaignDesktopPage, self).RunNavigateSteps(action_runner)
-
-  def RunPageInteractions(self, action_runner):
-    action_runner.WaitForElement(text='Welcome to AdWords!')
-    action_runner.ExecuteJavaScript(
-        'console.timeEnd({{ label }});', label=INTERACTION_NAME)
diff --git a/tools/perf/page_sets/loading_desktop.py b/tools/perf/page_sets/loading_desktop.py
index dc4e8ff..1ee6f1c 100644
--- a/tools/perf/page_sets/loading_desktop.py
+++ b/tools/perf/page_sets/loading_desktop.py
@@ -108,3 +108,9 @@
           self.AddStory(page_cycler_story.PageCyclerStory(url, self,
               shared_page_state_class=shared_page_state.SharedMobilePageState,
               cache_temperature=temp, tags=tags, name=name))
+
+
+class LoadingDesktopExpectations(story.expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory(
+        'uol.com.br', [story.expectations.ALL_LINUX], 'crbug.com/723783')
diff --git a/tools/perf/page_sets/system_health/background_stories.py b/tools/perf/page_sets/system_health/background_stories.py
index 59b4c13..1d4bc27e 100644
--- a/tools/perf/page_sets/system_health/background_stories.py
+++ b/tools/perf/page_sets/system_health/background_stories.py
@@ -24,6 +24,10 @@
     action_runner.tab.browser.Background()
     super(_BackgroundStory, self)._Measure(action_runner)
 
+  @classmethod
+  def GenerateStoryDescription(cls):
+    return 'Load %s, then put the browser into the background.' % cls.URL
+
 
 class BackgroundGoogleStory(_BackgroundStory):
   NAME = 'background:search:google'
@@ -43,7 +47,6 @@
 
 
 class BackgroundNytimesMobileStory(_BackgroundStory):
-  """The third top website in http://www.alexa.com/topsites/category/News"""
   NAME = 'background:news:nytimes'
   URL = 'http://www.nytimes.com/2016/10/04/us/politics/vice-presidential-debate.html?_r=0'
   SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 75ba50a2..bdf4882 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -50,6 +50,10 @@
     action_runner.NavigateBack()
     self._WaitForNavigation(action_runner)
 
+  @classmethod
+  def GenerateStoryDescription(cls):
+    return 'Load %s and navigate to some items/articles.' % cls.URL
+
 
 class _ArticleBrowsingStory(_BrowsingStory):
   """Abstract base class for user stories browsing news / shopping articles.
@@ -385,8 +389,6 @@
   TAGS = [story_tags.EMERGING_MARKET]
 
 
-# crbug.com/704197 for win and mac
-@decorators.Disabled('win', 'mac')
 class ImgurDesktopStory(_MediaBrowsingStory):
   NAME = 'browse:media:imgur'
   URL = 'http://imgur.com/gallery/5UlBN'
@@ -396,6 +398,9 @@
 
 
 class YouTubeMobileStory(_MediaBrowsingStory):
+  """Load a typical YouTube video then navigate to a next few videos. Stop and
+  watch each video for few seconds.
+  """
   NAME = 'browse:media:youtube'
   URL = 'https://m.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false'
   ITEM_SELECTOR = '._mhgb > a'
@@ -407,6 +412,9 @@
 
 
 class YouTubeDesktopStory(_MediaBrowsingStory):
+  """Load a typical YouTube video then navigate to a next few videos. Stop and
+  watch each video for a few seconds.
+  """
   NAME = 'browse:media:youtube'
   URL = 'https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false'
   ITEM_SELECTOR = '.yt-uix-simple-thumb-related'
@@ -421,6 +429,9 @@
 
 
 class FacebookPhotosMobileStory(_MediaBrowsingStory):
+  """Load a photo page from Rihanna's facebook page then navigate a few next
+  photos.
+  """
   NAME = 'browse:media:facebook_photos'
   URL = (
       'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&source=54&ref=page_internal')
@@ -432,6 +443,9 @@
 
 
 class FacebookPhotosDesktopStory(_MediaBrowsingStory):
+  """Load a photo page from Rihanna's facebook page then navigate a few next
+  photos.
+  """
   NAME = 'browse:media:facebook_photos'
   URL = (
       'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&theater')
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index b5c99a1..f85a2a3 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -16,6 +16,10 @@
   """Abstract base class for single-page System Health user stories."""
   ABSTRACT_STORY = True
 
+  @classmethod
+  def GenerateStoryDescription(cls):
+    return 'Load %s' % cls.URL
+
 
 ################################################################################
 # Search and e-commerce.
@@ -269,6 +273,7 @@
 
 
 class LoadFacebookPhotosMobileStory(_LoadingStory):
+  """Load a page of rihanna's facebook with a photo."""
   NAME = 'load:media:facebook_photos'
   URL = (
       'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&source=54&ref=page_internal')
@@ -277,6 +282,7 @@
 
 
 class LoadFacebookPhotosDesktopStory(_LoadingStory):
+  """Load a page of rihanna's facebook with a photo."""
   NAME = 'load:media:facebook_photos'
   URL = (
       'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&theater')
@@ -291,6 +297,7 @@
 
 
 class LoadDocsStory(_LoadingStory):
+  """Load a typical google doc page."""
   NAME = 'load:tools:docs'
   URL = (
       'https://docs.google.com/document/d/1GvzDP-tTLmJ0myRhUAfTYWs3ZUFilUICg8psNHyccwQ/edit?usp=sharing')
@@ -337,6 +344,7 @@
         'document.getElementById("apploadingdiv").style.height === "0px"')
 
 class LoadStackOverflowStory(_LoadingStory):
+  """Load a typical question & answer page of stackoverflow.com"""
   NAME = 'load:tools:stackoverflow'
   URL = (
       'https://stackoverflow.com/questions/36827659/compiling-an-application-for-use-in-highly-radioactive-environments')
@@ -372,6 +380,7 @@
 
 
 class LoadBubblesStory(_LoadingStory):
+  """Load "smarty bubbles" game on famobi.com"""
   NAME = 'load:games:bubbles'
   URL = (
       'https://games.cdn.famobi.com/html5games/s/smarty-bubbles/v010/?fg_domain=play.famobi.com&fg_uid=d8f24956-dc91-4902-9096-a46cb1353b6f&fg_pid=4638e320-4444-4514-81c4-d80a8c662371&fg_beat=620')
diff --git a/tools/perf/page_sets/system_health/long_running_stories.py b/tools/perf/page_sets/system_health/long_running_stories.py
index a32ea45..6f1a947 100644
--- a/tools/perf/page_sets/system_health/long_running_stories.py
+++ b/tools/perf/page_sets/system_health/long_running_stories.py
@@ -30,6 +30,15 @@
       if self._take_memory_measurement:
         action_runner.MeasureMemory()
 
+  @classmethod
+  def GenerateStoryDescription(cls):
+    if cls.BACKGROUND:
+      return ('Load %s then open a new blank tab and let the loaded page stay '
+              'in background for %s seconds.' % (cls.URL, IDLE_TIME_IN_SECONDS))
+    else:
+      return ('Load %s then let it stay in foreground for %s seconds.' %
+              (cls.URL, IDLE_TIME_IN_SECONDS))
+
 
 ##############################################################################
 # Long running Gmail stories.
@@ -83,12 +92,10 @@
         'document.getElementById("loading").style.display === "none"')
 
 
-@decorators.Disabled('android')  # crbug.com/657433
 class LongRunningGmailMobileForegroundStory(_LongRunningGmailMobileBase):
   NAME = 'long_running:tools:gmail-foreground'
 
 
-@decorators.Disabled('all')  # crbug.com/681839
 class LongRunningGmailDesktopForegroundStory(_LongRunningGmailDesktopBase):
   NAME = 'long_running:tools:gmail-foreground'
 
diff --git a/tools/perf/page_sets/system_health/media_stories.py b/tools/perf/page_sets/system_health/media_stories.py
index ad079e8..14edfac 100644
--- a/tools/perf/page_sets/system_health/media_stories.py
+++ b/tools/perf/page_sets/system_health/media_stories.py
@@ -58,6 +58,7 @@
 
 @benchmark.Disabled('all')  # crbug.com/649392
 class GooglePlayMusicDesktopStory(_MediaStory):
+  """Browse the songs list in music.google.com, then play a song."""
   NAME = 'play:media:google_play_music'
   URL = 'https://music.google.com'
 
@@ -83,6 +84,7 @@
 
 @benchmark.Disabled('win')  # crbug.com/649392
 class SoundCloudDesktopStory(_MediaStory):
+  """Load soundcloud.com, search for "Smooth Jazz", then play a song."""
   NAME = 'play:media:soundcloud'
   URL = 'https://soundcloud.com'
 
@@ -101,6 +103,7 @@
 
 @decorators.Disabled('all')  # crbug.com/649392
 class PandoraDesktopStory(_MediaStory):
+  """Load pandora.com, then play a song."""
   NAME = 'play:media:pandora'
   URL = 'https://pandora.com'
 
diff --git a/tools/perf/page_sets/system_health/multi_tab_stories.py b/tools/perf/page_sets/system_health/multi_tab_stories.py
index fef8486..0b24512cb 100644
--- a/tools/perf/page_sets/system_health/multi_tab_stories.py
+++ b/tools/perf/page_sets/system_health/multi_tab_stories.py
@@ -9,8 +9,6 @@
 from page_sets.system_health import story_tags
 from page_sets.system_health import platforms
 
-from telemetry import benchmark
-
 
 class MultiTabStory(system_health_story.SystemHealthStory):
   ABSTRACT_STORY = True
@@ -44,8 +42,8 @@
       tab.WaitForFrameToBeDisplayed()
 
 
-@benchmark.Disabled('all')  # crbug.com/704197
 class MultiTabTypical24Story(MultiTabStory):
+  """Load 24 different web sites in 24 tabs, then cycle through each tab."""
   NAME = 'multitab:misc:typical24'
   TAGS = [story_tags.TABS_SWITCHING]
   URL_LIST = [
diff --git a/tools/perf/page_sets/system_health/searching_stories.py b/tools/perf/page_sets/system_health/searching_stories.py
index bdbc046..8285c29 100644
--- a/tools/perf/page_sets/system_health/searching_stories.py
+++ b/tools/perf/page_sets/system_health/searching_stories.py
@@ -13,6 +13,13 @@
 
 # TODO(ssid): Rename the search stories to browse stories crbug.com/708300.
 class SearchGoogleStory(system_health_story.SystemHealthStory):
+  """ A typical Google search user story.
+  Issue the search query "what is science" in the search box and press Enter.
+  Wait for the search result page to be loaded, then scroll to the Wikipedia
+  result.
+  Navigate to wikipedia page by clicking on the result and wait for it to be
+  fully loaded.
+  """
   NAME = 'search:portal:google'
   URL = 'https://www.google.co.uk/'
   TAGS = [story_tags.EMERGING_MARKET]
@@ -74,12 +81,11 @@
 class MobileNewTabPageStory(system_health_story.SystemHealthStory):
   """Story that loads new tab page and performs searches.
 
-  For each of the search queries in |_SEARCH_TEXTS| below, this story does:
+  Given a list of typical search queries, this story does for each of them:
    - enter the search query on the new tab page search box
    - read results
    - navigates back to new tab page
   """
-
   NAME = 'browse:chrome:newtab'
   URL = 'chrome://newtab'
   _SEARCH_TEXTS = ['does google know everything',
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py
index aea6f800..62b6a6c3f 100644
--- a/tools/perf/page_sets/system_health/system_health_story.py
+++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -87,6 +87,21 @@
     self._take_memory_measurement = take_memory_measurement
 
   @classmethod
+  def GetStoryDescription(cls):
+    if cls.__doc__:
+      return cls.__doc__
+    return cls.GenerateStoryDescription()
+
+  @classmethod
+  def GenerateStoryDescription(cls):
+    """ Subclasses of SystemHealthStory can override this to auto generate
+    their story description.
+    However, it's recommended to use the Python docstring to describe the user
+    stories instead and this should only be used for very repetitive cases.
+    """
+    return None
+
+  @classmethod
   def CanRun(cls, possible_browser):
     if (decorators.ShouldSkip(cls, possible_browser)[0] or
         cls.ShouldDisable(possible_browser)):
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py
index 5d8f3f5..2cce60f 100644
--- a/tools/perf/page_sets/webrtc_cases.py
+++ b/tools/perf/page_sets/webrtc_cases.py
@@ -1,7 +1,6 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-import os
 
 from telemetry import story
 from telemetry.page import page as page_module
@@ -9,38 +8,34 @@
 
 class WebrtcPage(page_module.Page):
 
-  def __init__(self, url, page_set, name):
+  def __init__(self, url, page_set, name, tags):
     assert url.startswith('file://webrtc_cases/')
     super(WebrtcPage, self).__init__(
-        url=url, page_set=page_set, name=name)
-
-    with open(os.path.join(os.path.dirname(__file__),
-                           'webrtc_track_peerconnections.js')) as javascript:
-      self.script_to_evaluate_on_commit = javascript.read()
+        url=url, page_set=page_set, name=name, tags=tags)
 
 
-class Page1(WebrtcPage):
+class GetUserMedia(WebrtcPage):
   """Why: Acquires a high definition (720p) local stream."""
 
-  def __init__(self, page_set):
-    super(Page1, self).__init__(
+  def __init__(self, page_set, tags):
+    super(GetUserMedia, self).__init__(
         url='file://webrtc_cases/resolution.html',
         name='hd_local_stream_10s',
-        page_set=page_set)
+        page_set=page_set, tags=tags)
 
   def RunPageInteractions(self, action_runner):
     action_runner.ClickElement('button[id="hd"]')
     action_runner.Wait(10)
 
 
-class Page2(WebrtcPage):
+class VideoCall(WebrtcPage):
   """Why: Sets up a local video-only WebRTC 720p call for 45 seconds."""
 
-  def __init__(self, page_set):
-    super(Page2, self).__init__(
+  def __init__(self, page_set, tags):
+    super(VideoCall, self).__init__(
         url='file://webrtc_cases/constraints.html',
         name='720p_call_45s',
-        page_set=page_set)
+        page_set=page_set, tags=tags)
 
   def RunPageInteractions(self, action_runner):
     with action_runner.CreateInteraction('Action_Create_PeerConnection',
@@ -55,14 +50,14 @@
       action_runner.Wait(45)
 
 
-class Page3(WebrtcPage):
+class DataChannel(WebrtcPage):
   """Why: Transfer as much data as possible through a data channel in 20s."""
 
-  def __init__(self, page_set):
-    super(Page3, self).__init__(
+  def __init__(self, page_set, tags):
+    super(DataChannel, self).__init__(
         url='file://webrtc_cases/datatransfer.html',
         name='30s_datachannel_transfer',
-        page_set=page_set)
+        page_set=page_set, tags=tags)
 
   def RunPageInteractions(self, action_runner):
     # It won't have time to finish the 512 MB, but we're only interested in
@@ -72,74 +67,29 @@
     action_runner.Wait(30)
 
 
-class Page4(WebrtcPage):
-  """Why: Sets up a WebRTC audio call with Opus."""
+class AudioCall(WebrtcPage):
+  """Why: Sets up a WebRTC audio call."""
 
-  def __init__(self, page_set):
-    super(Page4, self).__init__(
-        url='file://webrtc_cases/audio.html?codec=OPUS',
-        name='audio_call_opus_10s',
-        page_set=page_set)
+  def __init__(self, page_set, codec, tags):
+    super(AudioCall, self).__init__(
+        url='file://webrtc_cases/audio.html?codec=%s' % codec,
+        name='audio_call_%s_10s' % codec.lower(),
+        page_set=page_set, tags=tags)
+    self.codec = codec
 
   def RunPageInteractions(self, action_runner):
-    action_runner.ExecuteJavaScript('codecSelector.value="OPUS";')
+    action_runner.ExecuteJavaScript('codecSelector.value="%s";' % self.codec)
     action_runner.ClickElement('button[id="callButton"]')
     action_runner.Wait(10)
 
-
-class Page5(WebrtcPage):
-  """Why: Sets up a WebRTC audio call with G722."""
-
-  def __init__(self, page_set):
-    super(Page5, self).__init__(
-        url='file://webrtc_cases/audio.html?codec=G722',
-        name='audio_call_g722_10s',
-        page_set=page_set)
-
-  def RunPageInteractions(self, action_runner):
-    action_runner.ExecuteJavaScript('codecSelector.value="G722";')
-    action_runner.ClickElement('button[id="callButton"]')
-    action_runner.Wait(10)
-
-
-class Page6(WebrtcPage):
-  """Why: Sets up a WebRTC audio call with PCMU."""
-
-  def __init__(self, page_set):
-    super(Page6, self).__init__(
-        url='file://webrtc_cases/audio.html?codec=PCMU',
-        name='audio_call_pcmu_10s',
-        page_set=page_set)
-
-  def RunPageInteractions(self, action_runner):
-    action_runner.ExecuteJavaScript('codecSelector.value="PCMU";')
-    action_runner.ClickElement('button[id="callButton"]')
-    action_runner.Wait(10)
-
-
-class Page7(WebrtcPage):
-  """Why: Sets up a WebRTC audio call with iSAC 16K."""
-
-  def __init__(self, page_set):
-    super(Page7, self).__init__(
-        url='file://webrtc_cases/audio.html?codec=ISAC_16K',
-        name='audio_call_isac16k_10s',
-        page_set=page_set)
-
-  def RunPageInteractions(self, action_runner):
-    action_runner.ExecuteJavaScript('codecSelector.value="ISAC/16000";')
-    action_runner.ClickElement('button[id="callButton"]')
-    action_runner.Wait(10)
-
-
-class Page8(WebrtcPage):
+class CanvasCapturePeerConnection(WebrtcPage):
   """Why: Sets up a canvas capture stream connection to a peer connection."""
 
-  def __init__(self, page_set):
-    super(Page8, self).__init__(
+  def __init__(self, page_set, tags):
+    super(CanvasCapturePeerConnection, self).__init__(
         url='file://webrtc_cases/canvas-capture.html',
         name='canvas_capture_peer_connection',
-        page_set=page_set)
+        page_set=page_set, tags=tags)
 
   def RunPageInteractions(self, action_runner):
     with action_runner.CreateInteraction('Action_Canvas_PeerConnection',
@@ -148,14 +98,14 @@
       action_runner.Wait(10)
 
 
-class Page9(WebrtcPage):
-  """Why: Sets up several peerconnections in the same page."""
+class MultiplePeerConnections(WebrtcPage):
+  """Why: Sets up several peer connections in the same page."""
 
-  def __init__(self, page_set):
-    super(Page9, self).__init__(
+  def __init__(self, page_set, tags):
+    super(MultiplePeerConnections, self).__init__(
         url='file://webrtc_cases/multiple-peerconnections.html',
         name='multiple_peerconnections',
-        page_set=page_set)
+        page_set=page_set, tags=tags)
 
   def RunPageInteractions(self, action_runner):
     with action_runner.CreateInteraction('Action_Create_PeerConnection',
@@ -169,65 +119,20 @@
       action_runner.Wait(45)
 
 
-class WebrtcGetusermediaPageSet(story.StorySet):
-  """WebRTC tests for local getUserMedia: video capture and playback."""
-
+class WebrtcPageSet(story.StorySet):
   def __init__(self):
-    super(WebrtcGetusermediaPageSet, self).__init__(
+    super(WebrtcPageSet, self).__init__(
         cloud_storage_bucket=story.PUBLIC_BUCKET)
 
-    self.AddStory(Page1(self))
-
-
-class WebrtcStresstestPageSet(story.StorySet):
-  """WebRTC stress-testing with multiple peer connections."""
-
-  def __init__(self):
-    super(WebrtcStresstestPageSet, self).__init__(
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
-
-    self.AddStory(Page9(self))
-
-
-class WebrtcPeerconnectionPageSet(story.StorySet):
-  """WebRTC tests for Real-time video and audio communication."""
-
-  def __init__(self):
-    super(WebrtcPeerconnectionPageSet, self).__init__(
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
-
-    self.AddStory(Page2(self))
-
-
-class WebrtcDatachannelPageSet(story.StorySet):
-  """WebRTC tests for Real-time communication via the data channel."""
-
-  def __init__(self):
-    super(WebrtcDatachannelPageSet, self).__init__(
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
-
-    self.AddStory(Page3(self))
-
-
-class WebrtcAudioPageSet(story.StorySet):
-  """WebRTC tests for Real-time audio communication."""
-
-  def __init__(self):
-    super(WebrtcAudioPageSet, self).__init__(
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
-
-    self.AddStory(Page4(self))
-    self.AddStory(Page5(self))
-    self.AddStory(Page6(self))
-    self.AddStory(Page7(self))
-
-
-class WebrtcRenderingPageSet(story.StorySet):
-  """WebRTC tests for video rendering."""
-
-  def __init__(self):
-    super(WebrtcRenderingPageSet, self).__init__(
-        cloud_storage_bucket=story.PARTNER_BUCKET)
-
-    self.AddStory(Page2(self))
-    self.AddStory(Page8(self))
+    self.AddStory(GetUserMedia(self, tags=['getusermedia']))
+    self.AddStory(MultiplePeerConnections(self, tags=['stress']))
+    self.AddStory(VideoCall(self, tags=['peerconnection', 'smoothness']))
+    self.AddStory(DataChannel(self, tags=['datachannel']))
+    self.AddStory(CanvasCapturePeerConnection(self, tags=['smoothness']))
+    # TODO(qyearsley, mcasas): Add webrtc.audio when http://crbug.com/468732
+    # is fixed, or revert https://codereview.chromium.org/1544573002/ when
+    # http://crbug.com/568333 is fixed.
+    # self.AddStory(AudioCall(self, 'OPUS'))
+    # self.AddStory(AudioCall(self, 'G772'))
+    # self.AddStory(AudioCall(self, 'PCMU'))
+    # self.AddStory(AudioCall(self, 'ISAC/1600'))
diff --git a/tools/perf/page_sets/webrtc_track_peerconnections.js b/tools/perf/page_sets/webrtc_track_peerconnections.js
deleted file mode 100644
index bb77bb6b..0000000
--- a/tools/perf/page_sets/webrtc_track_peerconnections.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file overwrites the RTCPeerConnection constructor with a new constructor
-// which tracks all created connections. It does this by periodically gathering
-// statistics on all connections, using the WebRTC statistics API. All reports
-// are gathered into window.peerConnectionReports, which contains one list per
-// connection. In each list there is a number of report batches, which in turn
-// contains metric names mapped to values.
-
-window.peerConnectionReports = [];
-
-RTCPeerConnection = webkitRTCPeerConnection = (function() {
-  function getReportsAsDicts(getStatsResult) {
-    var result = [];
-    getStatsResult.forEach(function(report) {
-      var values = {};
-      report.names().forEach(function(name) {
-        values[name] = report.stat(name);
-      });
-      result.push(values);
-    });
-    return result;
-  }
-
-  function gatherStatsFromOneConnection(peerConnection) {
-    var connectionId = window.peerConnectionReports.length;
-    window.peerConnectionReports.push([]);
-    var pollIntervalMs = 1000;
-
-    setInterval(function() {
-      peerConnection.getStats(function(response) {
-        var reports = getReportsAsDicts(response.result());
-        window.peerConnectionReports[connectionId].push(reports);
-      });
-    }, pollIntervalMs);
-  }
-
-  var originalConstructor = RTCPeerConnection;
-  return function() {
-    // Bind the incoming arguments to the original constructor.
-    var args = [null].concat(Array.prototype.slice.call(arguments));
-    var factoryFunction = originalConstructor.bind.apply(
-      originalConstructor, args);
-
-    // Create the object and track it.
-    var peerConnection = new factoryFunction();
-    gatherStatsFromOneConnection(peerConnection);
-    return peerConnection;
-  }
-})();
diff --git a/tools/perf/system_health_stories.csv b/tools/perf/system_health_stories.csv
new file mode 100644
index 0000000..2d5947e
--- /dev/null
+++ b/tools/perf/system_health_stories.csv
@@ -0,0 +1,163 @@
+Story name,Platform,Description
+background:media:imgur,mobile,"Load http://imgur.com/gallery/hUita, then put the Chrome browser into the background."
+background:news:nytimes,mobile,"Load http://www.nytimes.com/2016/10/04/us/politics/vice-presidential-debate.html?_r=0, then put the Chrome browser into the background."
+background:search:google,mobile,"Load https://www.google.co.uk/#q=tom+cruise+movies, then put the Chrome browser into the background."
+background:social:facebook,mobile,"Load https://www.facebook.com/rihanna, then put the Chrome browser into the background."
+background:tools:gmail,mobile,Load https://mail.google.com/mail/
+blank:about:blank,all,Story that loads the about:blank page.
+browse:chrome:newtab,mobile,"Story that loads new tab page and performs searches.
+
+  For each of the search queries in in the list below, this story does:
+   - enter the search query on the new tab page search box
+   - read results
+   - navigates back to new tab page
+
+  List of search queries:
+    'does google know everything',
+    'most famous paintings',
+    'current weather',
+    'best movies 2016',
+    'how to tie a tie'
+  "
+browse:chrome:omnibox,mobile,"Story that peforms search by using omnibox search provider
+
+  Loads a website and enters a search query on omnibox and navigates to default
+  search provider (google).
+  "
+browse:media:facebook_photos,mobile,"Load a photo page from Rihanna's facebook page then navigate a few next
+  photos.
+  "
+browse:media:imgur,desktop,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles.
+browse:media:imgur,mobile,Load http://imgur.com/gallery/5UlBN and navigate to some items/articles.
+browse:media:pinterest,desktop,Load https://pinterest.com and navigate to some items/articles.
+browse:media:tumblr,desktop,Load https://tumblr.com/search/gifs and navigate to some items/articles.
+browse:media:youtube,desktop,"Load a typical YouTube video then navigate to a next few videos. Stop and
+  watch each video for a few seconds.
+  "
+browse:media:youtube,mobile,"Load a typical YouTube video then navigate to a next few videos. Stop and
+  watch each video for few seconds.
+  "
+browse:news:cnn,all,The second top website in http://www.alexa.com/topsites/category/News
+browse:news:cricbuzz,mobile,Load http://m.cricbuzz.com and navigate to some items/articles.
+browse:news:flipboard,desktop,Load https://flipboard.com/explore and navigate to some items/articles.
+browse:news:globo,mobile,Load http://www.globo.com and navigate to some items/articles.
+browse:news:hackernews,desktop,Load https://news.ycombinator.com and navigate to some items/articles.
+browse:news:nytimes,desktop,The third top website in http://www.alexa.com/topsites/category/News
+browse:news:qq,mobile,Load http://news.qq.com and navigate to some items/articles.
+browse:news:reddit,desktop,The top website in http://www.alexa.com/topsites/category/News
+browse:news:reddit,mobile,The top website in http://www.alexa.com/topsites/category/News
+browse:news:toi,mobile,Load http://m.timesofindia.com and navigate to some items/articles.
+browse:news:washingtonpost,mobile,Progressive website
+browse:search:google,desktop,"
+  A typical google search story:
+    _ Start at https://www.google.com/search?q=flower
+    _ Click on the wikipedia link & navigate to
+      https://en.wikipedia.org/wiki/Flower
+    _ Scroll down the wikipedia page about flower.
+    _ Back to the search main page.
+    _ Refine the search query to 'flower delivery'.
+    _ Scroll down the page.
+    _ Click the next page result of 'flower delivery'.
+    _ Scroll the search page.
+
+  "
+browse:search:google_india,desktop,"
+  A typical google search story in India:
+    1. Start at https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2`
+    2. Scroll down the page.
+    3. Refine the query & click search box, which navigates to
+    https://www.google.co.in/search?q=%E0%A4%AB%E0%A5%82%E0%A4%B2&rct=j#q=%E0%A4%AB%E0%A5%82%E0%A4%B2+%E0%A4%B5%E0%A4%BF%E0%A4%A4%E0%A4%B0%E0%A4%A3
+    4. Scroll down the page.
+    5. Click the next page result
+    6. Scroll the search result page.
+
+  "
+browse:shopping:amazon,mobile,Load https://www.amazon.co.in/s/?field-keywords=Mobile and navigate to some items/articles.
+browse:shopping:avito,mobile,Load https://www.avito.ru/rossiya and navigate to some items/articles.
+browse:shopping:flipkart,mobile,Load https://flipkart.com/search?q=Sunglasses and navigate to some items/articles.
+browse:shopping:lazada,mobile,Load https://www.lazada.co.id/catalog/?q=Wrist+watch and navigate to some items/articles.
+browse:social:facebook,mobile,Load https://www.facebook.com/rihanna and navigate to some items/articles.
+browse:social:instagram,mobile,Load https://www.instagram.com/badgalriri/ and navigate to some items/articles.
+browse:social:twitter,desktop,Load https://www.twitter.com/nasa and navigate to some items/articles.
+browse:social:twitter,mobile,Load https://www.twitter.com/nasa and navigate to some items/articles.
+browse:tools:earth,desktop,"
+  Google Earth story:
+    _ Start at https://www.maps.google.com/maps
+    _ Click on the Earth link
+    _ Click ZoomIn three times, waiting for 3 sec in between.
+
+  "
+browse:tools:maps,desktop,"
+  Google maps story:
+    _ Start at https://www.maps.google.com/maps
+    _ Search for ""restaurents near me"" and wait for 4 sec.
+    _ Click ZoomIn two times, waiting for 3 sec in between.
+    _ Scroll the map horizontally and vertically.
+    _ Pick a restaurant and ask for directions.
+  "
+browse:tools:maps,mobile,"Story that browses google maps mobile page
+
+  This story searches for nearby restaurants on google maps website and finds
+  directions to a chosen restaurant from search results.
+  "
+load:games:alphabetty,desktop,Load https://king.com/play/alphabetty
+load:games:bubbles,all,"Load ""smarty bubbles"" game on famobi.com"
+load:games:lazors,all,Load http://www8.games.mobi/games/html5/lazors/lazors.html
+load:games:miniclip,desktop,Load http://www.miniclip.com/games/en/
+load:games:spychase,all,Load http://playstar.mobi/games/spychase/index.php
+load:media:9gag,desktop,Load https://www.9gag.com/
+load:media:dailymotion,all,Load https://www.dailymotion.com/video/x489k7d_street-performer-shows-off-slinky-skills_fun?autoplay=false
+load:media:facebook_photos,mobile,Load a page of rihanna's facebook with a photo.
+load:media:flickr,desktop,Load https://www.flickr.com/photos/tags/farm
+load:media:google_images,all,Load https://www.google.co.uk/search?tbm=isch&q=love
+load:media:imgur,all,Load http://imgur.com/gallery/5UlBN
+load:media:soundcloud,all,Load https://soundcloud.com/lifeofdesiigner/desiigner-panda
+load:media:youtube,all,Load https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false
+load:news:bbc,desktop,Load https://www.bbc.co.uk/news/world-asia-china-36189636
+load:news:cnn,all,Load http://edition.cnn.com
+load:news:flipboard,desktop,Load https://flipboard.com/explore
+load:news:hackernews,desktop,Load https://news.ycombinator.com
+load:news:irctc,mobile,Load https://www.irctc.co.in
+load:news:nytimes,desktop,Load http://www.nytimes.com
+load:news:nytimes,mobile,Load http://mobile.nytimes.com
+load:news:qq,all,Load http://news.qq.com
+load:news:reddit,desktop,Load https://www.reddit.com/r/news/top/?sort=top&t=week
+load:news:reddit,mobile,Load https://www.reddit.com/r/news/top/?sort=top&t=week
+load:news:washingtonpost,mobile,Load https://www.washingtonpost.com/pwa
+load:news:wikipedia,all,Load https://en.wikipedia.org/wiki/Science
+load:search:amazon,desktop,Load https://www.amazon.com/s/?field-keywords=nexus
+load:search:baidu,all,Load https://www.baidu.com/s?word=google
+load:search:ebay,all,Load https://www.ebay.com/sch/i.html?_nkw=headphones
+load:search:google,all,Load https://www.google.co.uk/
+load:search:taobao,desktop,Load https://world.taobao.com/
+load:search:taobao,mobile,Load http://m.intl.taobao.com/?ali_trackid
+load:search:yahoo,all,Load https://search.yahoo.com/search;_ylt=?p=google
+load:search:yandex,all,Load https://yandex.ru/touchsearch?text=science
+load:social:facebook,all,Load https://www.facebook.com/rihanna
+load:social:instagram,desktop,Load https://www.instagram.com/selenagomez/
+load:social:pinterest,all,Load https://uk.pinterest.com/categories/popular/
+load:social:tumblr,all,Load https://50thousand.tumblr.com/
+load:social:twitter,all,Load https://www.twitter.com/nasa
+load:social:vk,desktop,Load https://vk.com/sbeatles
+load:tools:docs,all,Load a typical google doc page.
+load:tools:drive,all,Load https://drive.google.com/drive/my-drive
+load:tools:dropbox,all,Load https://www.dropbox.com
+load:tools:gmail,desktop,Load https://mail.google.com/mail/
+load:tools:gmail,mobile,Load https://mail.google.com/mail/
+load:tools:stackoverflow,all,Load a typical question & answer page of stackoverflow.com
+load:tools:weather,all,Load https://weather.com/en-GB/weather/today/l/USCA0286:1:US
+long_running:tools:gmail-background,desktop,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.
+long_running:tools:gmail-background,mobile,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.
+long_running:tools:gmail-foreground,desktop,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds.
+long_running:tools:gmail-foreground,mobile,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds.
+multitab:misc:typical24,desktop,"Load 24 different web sites in 24 tabs, then cycle through each tab."
+play:media:google_play_music,desktop,"Browse the songs list in music.google.com, then play a song."
+play:media:pandora,desktop,"Load pandora.com, then play a song."
+play:media:soundcloud,desktop,"Load soundcloud.com, search for ""Smooth Jazz"", then play a song."
+search:portal:google,all," A typical Google search user story.
+  Issue the search query ""what is science"" in the search box and press Enter.
+  Wait for the search result page to be loaded, then scroll to the Wikipedia
+  result.
+  Navigate to wikipedia page by clicking on the result and wait for it to be
+  fully loaded.
+  "
diff --git a/tools/perf/unowned_benchmarks.txt b/tools/perf/unowned_benchmarks.txt
index 375befb..0a64f8d 100644
--- a/tools/perf/unowned_benchmarks.txt
+++ b/tools/perf/unowned_benchmarks.txt
@@ -1,18 +1,8 @@
 blink_perf.blink_gc
-blink_style.key_mobile_sites
-blink_style.polymer
-blink_style.top_25
 blob_storage.blob_storage
-gpu_times.gpu_rasterization.key_mobile_sites_smooth
-gpu_times.gpu_rasterization.top_25_smooth
-gpu_times.key_mobile_sites_smooth
-gpu_times.top_25_smooth
 load_library_perf_tests
 power.idle_platform
 power.steady_state
-power.top_10
-power.top_25
-power.typical_10_mobile_reload
 rasterize_and_record_micro.key_mobile_sites
 rasterize_and_record_micro.partial_invalidation
 rasterize_and_record_micro.polymer
@@ -29,5 +19,3 @@
 thread_times.key_hit_test_cases
 thread_times.key_mobile_sites_smooth
 thread_times.key_noop_cases
-webrtc.getusermedia
-webrtc.peerconnection
diff --git a/tools/resource_prefetch_predictor/prefetch_predictor_tool.py b/tools/resource_prefetch_predictor/prefetch_predictor_tool.py
index 436e0216..71d8310f 100755
--- a/tools/resource_prefetch_predictor/prefetch_predictor_tool.py
+++ b/tools/resource_prefetch_predictor/prefetch_predictor_tool.py
@@ -84,8 +84,7 @@
   from resource_prefetch_predictor_pb2 import OriginData
   entry = OriginData()
   entry.ParseFromString(proto)
-  # For the offset, see kWindowsEpochDeltaMicroseconds in
-  # base/time/time_posix.cc.
+  # For the offset, see kTimeTToMicrosecondsOffset in base/time/time.h.
   last_visit_timestamp = int(entry.last_visit_time / 1e6 - 11644473600)
   formatted_last_visit_time = datetime.datetime.utcfromtimestamp(
       last_visit_timestamp).strftime('%Y-%m-%d %H:%M:%S')
diff --git a/tools/roll_angle.py b/tools/roll_angle.py
index a41673fc..b45b48c 100755
--- a/tools/roll_angle.py
+++ b/tools/roll_angle.py
@@ -30,12 +30,6 @@
     "buildernames": ["android_optional_gpu_tests_rel"]
   }
 ]
-extra_fyi_trybots = [
-  {
-    "mastername": "master.tryserver.chromium.win",
-    "buildernames": ["win_clang_dbg"]
-  }
-]
 
 SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
 SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
@@ -312,16 +306,6 @@
       base_try_cmd = ['git', 'cl', 'try']
       self._RunCommand(base_try_cmd)
 
-      if extra_cq_trybots:
-        # Run additional tryjobs.
-        # TODO(kbr): this should not be necessary -- the
-        # CQ_INCLUDE_TRYBOTS directive above should handle it.
-        # http://crbug.com/585237
-        self._TriggerExtraTrybots(extra_cq_trybots)
-
-      if extra_fyi_trybots:
-        self._TriggerExtraTrybots(extra_fyi_trybots)
-
       # Mark the CL to be committed if requested
       if should_commit:
         self._RunCommand(['git', 'cl', 'set-commit'])
diff --git a/tools/security/idn_test_case_generator.py b/tools/security/idn_test_case_generator.py
new file mode 100755
index 0000000..74edc0e
--- /dev/null
+++ b/tools/security/idn_test_case_generator.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python2
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utilities for generating IDN test cases.
+
+Either use the command-line interface (see --help) or directly call make_case
+from Python shell (see make_case documentation).
+"""
+
+import argparse
+import codecs
+import doctest
+import sys
+
+
+def str_to_c_string(string):
+    """Converts a Python str (ASCII) to a C string literal.
+
+    >>> str_to_c_string('abc\x8c')
+    '"abc\\\\x8c"'
+    """
+    return repr(string).replace("'", '"')
+
+
+def ishexdigit(c):
+    """
+    >>> ishexdigit('0')
+    True
+    >>> ishexdigit('9')
+    True
+    >>> ishexdigit('/')
+    False
+    >>> ishexdigit(':')
+    False
+    >>> ishexdigit('a')
+    True
+    >>> ishexdigit('f')
+    True
+    >>> ishexdigit('g')
+    False
+    >>> ishexdigit('A')
+    True
+    >>> ishexdigit('F')
+    True
+    >>> ishexdigit('G')
+    False
+    """
+    return c.isdigit() or ord('a') <= ord(c.lower()) <= ord('f')
+
+
+def unicode_to_c_wstring(string):
+    """Converts a Python str or unicode to a C wide-string literal.
+
+    >>> unicode_to_c_wstring(u'b\u00fccher.de')
+    'L"b\\\\x00fc" L"cher.de"'
+    """
+    result = ['L"']
+    for c in string:
+        # If the previous character was \x-escaped, and the next character is a
+        # hex digit, we need to end and restart the string literal. Otherwise,
+        # the next character will extend the \x escape sequence.
+        if result[-1].startswith('\\x') and ishexdigit(c):
+            result.append('" L"')
+        escaped = repr(c)[2:-1]
+        # Convert '\u' to '\x', and also force a minimum of 4 digits (this isn't
+        # necessary but is preferred style for these test cases).
+        if escaped[:2] in ('\\x', '\\u'):
+            escaped = '\\x%04x' % ord(c)
+        result.append(escaped)
+    result.append('"')
+    return ''.join(result)
+
+
+def make_case(unicode_domain, unicode_allowed=True, case_name=None):
+    """Generates a C++ test case for an IDN domain test.
+
+    This is designed specifically for the IDNTestCase struct in the file
+    components/url_formatter/url_formatter_unittest.cc. It generates a row of
+    the idn_cases array, specifying a test for a particular domain.
+
+    |unicode_domain| is a Unicode string of the domain (NOT IDNA-encoded).
+    |unicode_allowed| specifies whether the test case should expect the domain
+    to be displayed in Unicode form (True) or in IDNA/Punycode ASCII encoding
+    (False). |case_name| is just for the comment.
+
+    This function will automatically convert the domain to its IDNA format, and
+    prepare the test case in C++ syntax.
+
+    >>> make_case(u'\u5317\u4eac\u5927\u5b78.cn', True, 'Hanzi (Chinese)')
+      // Hanzi (Chinese)
+      {"xn--1lq90ic7f1rc.cn", L"\\x5317\\x4eac\\x5927\\x5b78.cn", true},
+    >>> make_case(u'b\u00fccher.de', True)
+      {"xn--bcher-kva.de", L"b\\x00fc" L"cher.de", true},
+
+    This will also apply normalization to the Unicode domain, as required by the
+    IDNA algorithm. This example shows U+210F normalized to U+0127 (this
+    generates the exact same test case as u'\u0127ello'):
+
+    >>> make_case(u'\u210fello', True)
+      {"xn--ello-4xa", L"\\x0127" L"ello", true},
+    """
+    idna_input = codecs.encode(unicode_domain, 'idna')
+    # Round-trip to ensure normalization.
+    unicode_output = codecs.decode(idna_input, 'idna')
+    if case_name:
+      print('  // %s' % case_name)
+    print('  {%s, %s, %s},' %
+          (str_to_c_string(idna_input), unicode_to_c_wstring(unicode_output),
+           repr(unicode_allowed).lower()))
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    parser = argparse.ArgumentParser(description='Generate an IDN test case.')
+    parser.add_argument('domain', metavar='DOMAIN', nargs='?',
+                        help='the Unicode domain (not encoded)')
+    parser.add_argument('--name', metavar='NAME',
+                        help='the name of the test case')
+    parser.add_argument('--no-unicode', action='store_false',
+                        dest='unicode_allowed', default=True,
+                        help='expect the domain to be Punycoded')
+    parser.add_argument('--test', action='store_true', dest='run_tests',
+                        help='run unit tests')
+
+    args = parser.parse_args(args)
+
+    if args.run_tests:
+        import doctest
+        doctest.testmod()
+        return
+
+    if not args.domain:
+        parser.error('Required argument: DOMAIN')
+
+    # Assume stdin.encoding is the encoding used for command-line arguments.
+    domain = args.domain.decode(sys.stdin.encoding)
+    make_case(domain, unicode_allowed=args.unicode_allowed, case_name=args.name)
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/tools/ubsan/vptr_blacklist.txt b/tools/ubsan/vptr_blacklist.txt
index e838203..c84a65d 100644
--- a/tools/ubsan/vptr_blacklist.txt
+++ b/tools/ubsan/vptr_blacklist.txt
@@ -100,6 +100,17 @@
 src:*third_party/swiftshader/third_party/LLVM*
 
 #############################################################################
+# UBSan yields false positives in libEGL when objects created in libGLESv2
+# from classes derived from libEGL base classes are used within libEGL.
+# UBSan wrongly detects that the libGLESv2 classes are not derived from libEGL
+# classes because libEGL doesn't know about libGLESv2 classes.
+# See crbug.com/722349.
+type:*egl*Context*
+type:*egl*Surface*
+type:*gl*Object*
+type:*sw*FrameBuffer*
+
+#############################################################################
 # UBSan seems to be emit false positives when virtual base classes are
 # involved, see e.g. crbug.com/448102.
 
diff --git a/tools/web_dev_style/OWNERS b/tools/web_dev_style/OWNERS
new file mode 100644
index 0000000..f8dba18
--- /dev/null
+++ b/tools/web_dev_style/OWNERS
@@ -0,0 +1,2 @@
+dbeam@chromium.org
+tbreisacher@chromium.org
diff --git a/tools/web_dev_style/PRESUBMIT.py b/tools/web_dev_style/PRESUBMIT.py
new file mode 100644
index 0000000..d808f851
--- /dev/null
+++ b/tools/web_dev_style/PRESUBMIT.py
@@ -0,0 +1,34 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def CheckChangeOnUpload(*args):
+  return _CommonChecks(*args)
+
+
+def CheckChangeOnCommit(*args):
+  return _CommonChecks(*args)
+
+
+def _CommonChecks(input_api, output_api):
+  cwd = input_api.PresubmitLocalPath()
+  path = input_api.os_path
+  files = [path.basename(f.LocalPath()) for f in input_api.AffectedFiles()]
+  tests = []
+
+  if 'css_checker.py' in files:
+    tests.append(path.join(cwd, 'css_checker_test.py'))
+
+  utils_changed = 'regex_check.py' in files or 'test_util.py' in files
+
+  if utils_changed or any(f for f in files if f.startswith('html_checker')):
+    tests.append(path.join(cwd, 'html_checker_test.py'))
+
+  if utils_changed or any(f for f in files if f.startswith('js_checker')):
+    tests.append(path.join(cwd, 'js_checker_test.py'))
+
+  if utils_changed or any(f for f in files if f.startswith('resource_checker')):
+    tests.append(path.join(cwd, 'resource_checker_test.py'))
+
+  return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
diff --git a/tools/web_dev_style/__init__.py b/tools/web_dev_style/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/web_dev_style/__init__.py
diff --git a/tools/web_dev_style/css_checker.py b/tools/web_dev_style/css_checker.py
new file mode 100644
index 0000000..0ac02ca
--- /dev/null
+++ b/tools/web_dev_style/css_checker.py
@@ -0,0 +1,432 @@
+# Copyright 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script for Chromium WebUI resources.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools, and see
+https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md
+for the rules we're checking against here.
+"""
+
+# TODO(dbeam): Real CSS parser? https://github.com/danbeam/css-py/tree/css3
+
+class CSSChecker(object):
+  def __init__(self, input_api, output_api, file_filter=None):
+    self.input_api = input_api
+    self.output_api = output_api
+    self.file_filter = file_filter
+
+  def RunChecks(self):
+    # We use this a lot, so make a nick name variable.
+    re = self.input_api.re
+
+    def _collapseable_hex(s):
+      return (len(s) == 6 and s[0] == s[1] and s[2] == s[3] and s[4] == s[5])
+
+    def _is_gray(s):
+      return s[0] == s[1] == s[2] if len(s) == 3 else s[0:2] == s[2:4] == s[4:6]
+
+    def _remove_all(s):
+      s = _remove_grit(s)  # Must be done first.
+      s = _remove_ats(s)
+      s = _remove_comments(s)
+      s = _remove_mixins_and_valid_vars(s)
+      s = _remove_template_expressions(s)
+      return s
+
+    def _extract_inline_style(s):
+      return '\n'.join(re.findall(r'<style\b[^>]*>([^<]*)<\/style>', s))
+
+    def _remove_ats(s):
+      return re.sub(r"""
+          @(?!apply)(?!\d+x\b)    # @at-keyword, not (apply|2x)
+          \w+[^'"]*?{             # selector junk {
+          (.*{.*?})+              # inner { curly } blocks, rules, and selector
+          .*?}                    # stuff up to the first end curly }
+          """, r'\1', s, flags=re.DOTALL | re.VERBOSE)
+
+    def _remove_comments(s):
+      return re.sub(r'/\*.*?\*/', '', s, flags=re.DOTALL)
+
+    def _remove_grit(s):
+      return re.sub(r"""
+          <if[^>]+>.*?<\s*/\s*if[^>]*>|  # <if> contents </if>
+          <include[^>]+>                 # <include>
+          """, '', s, flags=re.DOTALL | re.VERBOSE)
+
+    mixin_shim_reg = r'[\w-]+_-_[\w-]+'
+
+    def _remove_mixins_and_valid_vars(s):
+      valid_vars = r'--(?!' + mixin_shim_reg + r')[\w-]+:\s*'
+      mixin_or_value = r'({.*?}|[^;}]+);?\s*'
+      return re.sub(valid_vars + mixin_or_value, '', s, flags=re.DOTALL)
+
+    def _remove_template_expressions(s):
+      return re.sub(r'\$i18n(Raw)?{[^}]*}', '', s, flags=re.DOTALL)
+
+    def _rgb_from_hex(s):
+      if len(s) == 3:
+        r, g, b = s[0] + s[0], s[1] + s[1], s[2] + s[2]
+      else:
+        r, g, b = s[0:2], s[2:4], s[4:6]
+      return int(r, base=16), int(g, base=16), int(b, base=16)
+
+    def _strip_prefix(s):
+      return re.sub(r'^-(?:o|ms|moz|khtml|webkit)-', '', s)
+
+    def alphabetize_props(contents):
+      errors = []
+      # TODO(dbeam): make this smart enough to detect issues in mixins.
+      for rule in re.finditer(r'{(.*?)}', contents, re.DOTALL):
+        semis = map(lambda t: t.strip(), rule.group(1).split(';'))[:-1]
+        rules = filter(lambda r: ': ' in r, semis)
+        props = map(lambda r: r[0:r.find(':')], rules)
+        if props != sorted(props):
+          errors.append('    %s;\n' % (';\n    '.join(rules)))
+      return errors
+
+    def braces_have_space_before_and_nothing_after(line):
+      brace_space_reg = re.compile(r"""
+          (?:^|\S){|  # selector{ or selector\n{ or
+          {\s*\S+\s*  # selector { with stuff after it
+          $           # must be at the end of a line
+          """,
+          re.VERBOSE)
+      return brace_space_reg.search(line)
+
+    def classes_use_dashes(line):
+      # Intentionally dumbed down version of CSS 2.1 grammar for class without
+      # non-ASCII, escape chars, or whitespace.
+      class_reg = re.compile(r"""
+          (?<!')\.(-?[\w-]+).*  # ., then maybe -, then alpha numeric and -
+          [,{]\s*$              # selectors should end with a , or {
+          """,
+          re.VERBOSE)
+      m = class_reg.search(line)
+      if not m:
+        return False
+      class_name = m.group(1)
+      return class_name.lower() != class_name or '_' in class_name
+
+    end_mixin_reg = re.compile(r'\s*};\s*$')
+
+    def close_brace_on_new_line(line):
+      # Ignore single frames in a @keyframe, i.e. 0% { margin: 50px; }
+      frame_reg = re.compile(r"""
+          \s*(from|to|\d+%)\s*{     # 50% {
+          \s*[\w-]+:                # rule:
+          (\s*[\w\(\), -\.]+)+\s*;  # value;
+          \s*}\s*                   # }
+          """,
+          re.VERBOSE)
+      return ('}' in line and re.search(r'[^ }]', line) and
+              not frame_reg.match(line) and not end_mixin_reg.match(line))
+
+    def colons_have_space_after(line):
+      colon_space_reg = re.compile(r"""
+          (?<!data)    # ignore data URIs
+          :(?!//)      # ignore url(http://), etc.
+          \S[^;]+;\s*  # only catch one-line rules for now
+          """,
+          re.VERBOSE)
+      return colon_space_reg.search(line)
+
+    def favor_single_quotes(line):
+      return '"' in line
+
+    # Shared between hex_could_be_shorter and rgb_if_not_gray.
+    hex_reg = re.compile(r"""
+        \#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})  # pound followed by 3 or 6 hex digits
+        (?=[^\w-]|$)                       # no more alphanum chars or at EOL
+        (?!.*(?:{.*|,\s*)$)                # not in a selector
+        """,
+        re.VERBOSE)
+
+    def hex_could_be_shorter(line):
+      m = hex_reg.search(line)
+      return (m and _is_gray(m.group(1)) and _collapseable_hex(m.group(1)))
+
+    def rgb_if_not_gray(line):
+      m = hex_reg.search(line)
+      return (m and not _is_gray(m.group(1)))
+
+    small_seconds_reg = re.compile(r"""
+        (?:^|[^\w-])   # start of a line or a non-alphanumeric char
+        (0?\.[0-9]+)s  # 1.0s
+        (?!-?[\w-])    # no following - or alphanumeric chars
+        """,
+        re.VERBOSE)
+
+    def milliseconds_for_small_times(line):
+      return small_seconds_reg.search(line)
+
+    def suggest_ms_from_s(line):
+      ms = int(float(small_seconds_reg.search(line).group(1)) * 1000)
+      return ' (replace with %dms)' % ms
+
+    def no_data_uris_in_source_files(line):
+      return re.search(r'\(\s*\s*data:', line)
+
+    def no_mixin_shims(line):
+      return re.search(r'--' + mixin_shim_reg + r'\s*:', line)
+
+    def no_quotes_in_url(line):
+      return re.search('url\s*\(\s*["\']', line, re.IGNORECASE)
+
+    def one_rule_per_line(line):
+      one_rule_reg = re.compile(r"""
+          [\w-](?<!data):  # a rule: but no data URIs
+          (?!//)[^;]+;     # value; ignoring colons in protocols:// and };
+          \s*[^ }]\s*      # any non-space after the end colon
+          """,
+          re.VERBOSE)
+      return one_rule_reg.search(line) and not end_mixin_reg.match(line)
+
+    def pseudo_elements_double_colon(contents):
+      pseudo_elements = ['after',
+                         'before',
+                         'calendar-picker-indicator',
+                         'color-swatch',
+                         'color-swatch-wrapper',
+                         'date-and-time-container',
+                         'date-and-time-value',
+                         'datetime-edit',
+                         'datetime-edit-ampm-field',
+                         'datetime-edit-day-field',
+                         'datetime-edit-hour-field',
+                         'datetime-edit-millisecond-field',
+                         'datetime-edit-minute-field',
+                         'datetime-edit-month-field',
+                         'datetime-edit-second-field',
+                         'datetime-edit-text',
+                         'datetime-edit-week-field',
+                         'datetime-edit-year-field',
+                         'details-marker',
+                         'file-upload-button',
+                         'first-letter',
+                         'first-line',
+                         'inner-spin-button',
+                         'input-placeholder',
+                         'input-speech-button',
+                         'media-slider-container',
+                         'media-slider-thumb',
+                         'meter-bar',
+                         'meter-even-less-good-value',
+                         'meter-inner-element',
+                         'meter-optimum-value',
+                         'meter-suboptimum-value',
+                         'progress-bar',
+                         'progress-inner-element',
+                         'progress-value',
+                         'resizer',
+                         'scrollbar',
+                         'scrollbar-button',
+                         'scrollbar-corner',
+                         'scrollbar-thumb',
+                         'scrollbar-track',
+                         'scrollbar-track-piece',
+                         'search-cancel-button',
+                         'search-decoration',
+                         'search-results-button',
+                         'search-results-decoration',
+                         'selection',
+                         'slider-container',
+                         'slider-runnable-track',
+                         'slider-thumb',
+                         'textfield-decoration-container',
+                         'validation-bubble',
+                         'validation-bubble-arrow',
+                         'validation-bubble-arrow-clipper',
+                         'validation-bubble-heading',
+                         'validation-bubble-message',
+                         'validation-bubble-text-block']
+      pseudo_reg = re.compile(r"""
+          (?<!:):       # a single colon, i.e. :after but not ::after
+          ([a-zA-Z-]+)  # a pseudo element, class, or function
+          (?=[^{}]+?{)  # make sure a selector, not inside { rules }
+          """,
+          re.MULTILINE | re.VERBOSE)
+      errors = []
+      for p in re.finditer(pseudo_reg, contents):
+        pseudo = p.group(1).strip().splitlines()[0]
+        if _strip_prefix(pseudo.lower()) in pseudo_elements:
+          errors.append('    :%s (should be ::%s)' % (pseudo, pseudo))
+      return errors
+
+    def one_selector_per_line(contents):
+      any_reg = re.compile(r"""
+          :(?:-webkit-)?any\(.*?\)  # :-webkit-any(a, b, i) selector
+          """,
+          re.DOTALL | re.VERBOSE)
+      multi_sels_reg = re.compile(r"""
+          (?:}\s*)?            # ignore 0% { blah: blah; }, from @keyframes
+          ([^,]+,(?=[^{}]+?{)  # selector junk {, not in a { rule }
+          .*[,{])\s*$          # has to end with , or {
+          """,
+          re.MULTILINE | re.VERBOSE)
+      errors = []
+      for b in re.finditer(multi_sels_reg, re.sub(any_reg, '', contents)):
+        errors.append('    ' + b.group(1).strip().splitlines()[-1:][0])
+      return errors
+
+    def suggest_rgb_from_hex(line):
+      suggestions = ['rgb(%d, %d, %d)' % _rgb_from_hex(h.group(1))
+          for h in re.finditer(hex_reg, line)]
+      return ' (replace with %s)' % ', '.join(suggestions)
+
+    def suggest_short_hex(line):
+      h = hex_reg.search(line).group(1)
+      return ' (replace with #%s)' % (h[0] + h[2] + h[4])
+
+    webkit_before_or_after_reg = re.compile(r'-webkit-(\w+-)(after|before):')
+
+    def suggest_top_or_bottom(line):
+      prop, pos = webkit_before_or_after_reg.search(line).groups()
+      top_or_bottom = 'top' if pos == 'before' else 'bottom'
+      return ' (replace with %s)' % (prop + top_or_bottom)
+
+    def webkit_before_or_after(line):
+      return webkit_before_or_after_reg.search(line)
+
+    def zero_width_lengths(contents):
+      hsl_reg = re.compile(r"""
+          hsl\([^\)]*       # hsl(maybestuff
+          (?:[, ]|(?<=\())  # a comma or space not followed by a (
+          (?:0?\.?)?0%      # some equivalent to 0%
+          """,
+          re.VERBOSE)
+      zeros_reg = re.compile(r"""
+          ^.*(?:^|[^0-9.])              # start/non-number
+          (?:\.0|0(?:\.0?               # .0, 0, or 0.0
+          |px|em|%|in|cm|mm|pc|pt|ex))  # a length unit
+          (?!svg|png|jpg)(?:\D|$)       # non-number/end
+          (?=[^{}]+?}).*$               # only { rules }
+          """,
+          re.MULTILINE | re.VERBOSE)
+      errors = []
+      for z in re.finditer(zeros_reg, contents):
+        first_line = z.group(0).strip().splitlines()[0]
+        if not hsl_reg.search(first_line):
+          errors.append('    ' + first_line)
+      return errors
+
+    # NOTE: Currently multi-line checks don't support 'after'. Instead, add
+    # suggestions while parsing the file so another pass isn't necessary.
+    added_or_modified_files_checks = [
+        { 'desc': 'Alphabetize properties and list vendor specific (i.e. '
+                  '-webkit) above standard.',
+          'test': alphabetize_props,
+          'multiline': True,
+        },
+        { 'desc': 'Start braces ({) end a selector, have a space before them '
+                  'and no rules after.',
+          'test': braces_have_space_before_and_nothing_after,
+        },
+        { 'desc': 'Classes use .dash-form.',
+          'test': classes_use_dashes,
+        },
+        { 'desc': 'Always put a rule closing brace (}) on a new line.',
+          'test': close_brace_on_new_line,
+        },
+        { 'desc': 'Colons (:) should have a space after them.',
+          'test': colons_have_space_after,
+        },
+        { 'desc': 'Use single quotes (\') instead of double quotes (") in '
+                  'strings.',
+          'test': favor_single_quotes,
+        },
+        { 'desc': 'Use abbreviated hex (#rgb) when in form #rrggbb.',
+          'test': hex_could_be_shorter,
+          'after': suggest_short_hex,
+        },
+        { 'desc': 'Use milliseconds for time measurements under 1 second.',
+          'test': milliseconds_for_small_times,
+          'after': suggest_ms_from_s,
+        },
+        { 'desc': "Don't use data URIs in source files. Use grit instead.",
+          'test': no_data_uris_in_source_files,
+        },
+        { 'desc': "Don't override custom properties created by Polymer's mixin "
+                  "shim. Set mixins or documented custom properties directly.",
+          'test': no_mixin_shims,
+        },
+        { 'desc': "Don't use quotes in url().",
+          'test': no_quotes_in_url,
+        },
+        { 'desc': 'One rule per line (what not to do: color: red; margin: 0;).',
+          'test': one_rule_per_line,
+        },
+        { 'desc': 'One selector per line (what not to do: a, b {}).',
+          'test': one_selector_per_line,
+          'multiline': True,
+        },
+        { 'desc': 'Pseudo-elements should use double colon (i.e. ::after).',
+          'test': pseudo_elements_double_colon,
+          'multiline': True,
+        },
+        { 'desc': 'Use rgb() over #hex when not a shade of gray (like #333).',
+          'test': rgb_if_not_gray,
+          'after': suggest_rgb_from_hex,
+        },
+        { 'desc': 'Use *-top/bottom instead of -webkit-*-before/after.',
+          'test': webkit_before_or_after,
+          'after': suggest_top_or_bottom,
+        },
+        { 'desc': 'Use "0" for zero-width lengths (i.e. 0px -> 0)',
+          'test': zero_width_lengths,
+          'multiline': True,
+        },
+    ]
+
+    results = []
+    affected_files = self.input_api.AffectedFiles(include_deletes=False,
+                                                  file_filter=self.file_filter)
+    files = []
+    for f in affected_files:
+      path = f.LocalPath()
+
+      is_html = path.endswith('.html')
+      if not is_html and not path.endswith('.css'):
+        continue
+
+      # Remove all /*comments*/, @at-keywords, and grit <if|include> tags; we're
+      # not using a real parser. TODO(dbeam): Check alpha in <if> blocks.
+      file_contents = _remove_all('\n'.join(f.NewContents()))
+
+      # Handle CSS files and HTML files with inline styles.
+      if is_html:
+        file_contents = _extract_inline_style(file_contents)
+
+      files.append((path, file_contents))
+
+    for f in files:
+      file_errors = []
+      for check in added_or_modified_files_checks:
+        # If the check is multiline, it receives the whole file and gives us
+        # back a list of things wrong. If the check isn't multiline, we pass it
+        # each line and the check returns something truthy if there's an issue.
+        if ('multiline' in check and check['multiline']):
+          assert not 'after' in check
+          check_errors = check['test'](f[1])
+          if len(check_errors) > 0:
+            file_errors.append('- %s\n%s' %
+                (check['desc'], '\n'.join(check_errors).rstrip()))
+        else:
+          check_errors = []
+          lines = f[1].splitlines()
+          for lnum, line in enumerate(lines):
+            if check['test'](line):
+              error = '    ' + line.strip()
+              if 'after' in check:
+                error += check['after'](line)
+              check_errors.append(error)
+          if len(check_errors) > 0:
+            file_errors.append('- %s\n%s' %
+                (check['desc'], '\n'.join(check_errors)))
+      if file_errors:
+        results.append(self.output_api.PresubmitPromptWarning(
+            '%s:\n%s' % (f[0], '\n\n'.join(file_errors))))
+
+    return results
diff --git a/tools/web_dev_style/css_checker_test.py b/tools/web_dev_style/css_checker_test.py
new file mode 100755
index 0000000..b7fcb7dc
--- /dev/null
+++ b/tools/web_dev_style/css_checker_test.py
@@ -0,0 +1,520 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import css_checker
+from os import path as os_path
+import re
+from sys import path as sys_path
+import unittest
+
+_HERE = os_path.dirname(os_path.abspath(__file__))
+sys_path.append(os_path.join(_HERE, '..', '..', 'build'))
+
+import find_depot_tools  # pylint: disable=W0611
+from testing_support.super_mox import SuperMoxTestBase
+
+
+class CssCheckerTest(SuperMoxTestBase):
+  def setUp(self):
+    SuperMoxTestBase.setUp(self)
+
+    self.fake_file = self.mox.CreateMockAnything()
+    # Actual calls to NewContents() and LocalPath() are defined in each test.
+    self.mox.StubOutWithMock(self.fake_file, 'LocalPath')
+    self.mox.StubOutWithMock(self.fake_file, 'NewContents')
+
+    self.input_api = self.mox.CreateMockAnything()
+    self.input_api.re = re
+    self.mox.StubOutWithMock(self.input_api, 'AffectedSourceFiles')
+    self.input_api.AffectedFiles(
+        include_deletes=False, file_filter=None).AndReturn([self.fake_file])
+
+    # Actual creations of PresubmitPromptWarning are defined in each test.
+    self.output_api = self.mox.CreateMockAnything()
+    self.mox.StubOutWithMock(self.output_api, 'PresubmitPromptWarning',
+                             use_mock_anything=True)
+
+    self.output_api = self.mox.CreateMockAnything()
+    self.mox.StubOutWithMock(self.output_api, 'PresubmitNotifyResult',
+                             use_mock_anything=True)
+
+  def _create_file(self, contents, filename):
+    self.fake_file_name = filename
+    self.fake_file.LocalPath().AndReturn(self.fake_file_name)
+    self.fake_file.NewContents().AndReturn(contents.splitlines())
+
+  def VerifyContentIsValid(self, contents, filename='fake.css'):
+    self._create_file(contents, filename)
+    self.mox.ReplayAll()
+    css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
+
+  def VerifyContentsProducesOutput(self, contents, output, filename='fake.css'):
+    self._create_file(contents, filename)
+    self.output_api.PresubmitPromptWarning(
+        self.fake_file_name + ':\n' + output.strip()).AndReturn(None)
+    self.mox.ReplayAll()
+    css_checker.CSSChecker(self.input_api, self.output_api).RunChecks()
+
+  def testCssAlphaWithAtBlock(self):
+    self.VerifyContentsProducesOutput("""
+<include src="../shared/css/cr/ui/overlay.css">
+<include src="chrome://resources/totally-cool.css" />
+
+/* A hopefully safely ignored comment and @media statement. /**/
+@media print {
+  div {
+    display: block;
+    color: red;
+  }
+}
+
+.rule {
+  z-index: 5;
+<if expr="not is macosx">
+  background-image: url(chrome://resources/BLAH); /* TODO(dbeam): Fix this. */
+  background-color: rgb(235, 239, 249);
+</if>
+<if expr="is_macosx">
+  background-color: white;
+  background-image: url(chrome://resources/BLAH2);
+</if>
+  color: black;
+}
+
+<if expr="is_macosx">
+.language-options-right {
+  visibility: hidden;
+  opacity: 1; /* TODO(dbeam): Fix this. */
+}
+</if>""", """
+- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
+    display: block;
+    color: red;
+
+    z-index: 5;
+    color: black;""")
+
+  def testCssStringWithAt(self):
+    self.VerifyContentIsValid("""
+#logo {
+  background-image: url(images/google_logo.png@2x);
+}
+
+body.alternate-logo #logo {
+  -webkit-mask-image: url(images/google_logo.png@2x);
+  background: none;
+  @apply(--some-variable);
+}
+
+div {
+  -webkit-margin-start: 5px;
+}
+
+.stuff1 {
+}
+
+.stuff2 {
+}
+      """)
+
+  def testCssAlphaWithNonStandard(self):
+    self.VerifyContentsProducesOutput("""
+div {
+  /* A hopefully safely ignored comment and @media statement. /**/
+  color: red;
+  -webkit-margin-start: 5px;
+}""", """
+- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
+    color: red;
+    -webkit-margin-start: 5px;""")
+
+  def testCssAlphaWithLongerDashedProps(self):
+    self.VerifyContentsProducesOutput("""
+div {
+  border-left: 5px;  /* A hopefully removed comment. */
+  border: 5px solid red;
+}""", """
+- Alphabetize properties and list vendor specific (i.e. -webkit) above standard.
+    border-left: 5px;
+    border: 5px solid red;""")
+
+  def testCssAlphaWithVariables(self):
+    self.VerifyContentIsValid("""
+#id {
+  --zzyxx-xylophone: 3px;
+  --ignore-me: {
+    /* TODO(dbeam): fix this by creating a "sort context". If we simply strip
+     * off the mixin, the inside contents will be compared to the outside
+     * contents, which isn't what we want. */
+    visibility: hidden;
+    color: black;
+  };
+  --aardvark-animal: var(--zzyxz-xylophone);
+}
+""")
+
+  def testCssBracesHaveSpaceBeforeAndNothingAfter(self):
+    self.VerifyContentsProducesOutput("""
+/* Hello! */div/* Comment here*/{
+  display: block;
+}
+
+blah /* hey! */
+{
+  rule: value;
+}
+
+.mixed-in {
+  display: none;
+  --css-mixin: {
+    color: red;
+  };  /* This should be ignored. */
+}
+
+.this.is { /* allowed */
+  rule: value;
+}""", """
+- Start braces ({) end a selector, have a space before them and no rules after.
+    div{
+    {""")
+
+  def testCssClassesUseDashes(self):
+    self.VerifyContentsProducesOutput("""
+.className,
+.ClassName,
+.class-name /* We should not catch this. */,
+.class_name,
+[i18n-values*='.innerHTML:'] {
+  display: block;
+}""", """
+ - Classes use .dash-form.
+    .className,
+    .ClassName,
+    .class_name,""")
+
+  def testCssCloseBraceOnNewLine(self):
+    self.VerifyContentsProducesOutput("""
+@media { /* TODO(dbeam) Fix this case. */
+  .rule {
+    display: block;
+  }}
+
+@-webkit-keyframe blah {
+  from { height: rotate(-10turn); }
+  100% { height: 500px; }
+}
+
+#id { /* $i18n{*} and $i18nRaw{*} should be ignored. */
+  rule: $i18n{someValue};
+  rule2: $i18nRaw{someValue};
+  --css-mixin: {
+    color: red;
+  };
+}
+
+.paper-wrapper {
+  --paper-thinger: {
+    background: blue;
+  };
+}
+
+#rule {
+  rule: value; }""", """
+- Always put a rule closing brace (}) on a new line.
+    rule: value; }""")
+
+  def testCssColonsHaveSpaceAfter(self):
+    self.VerifyContentsProducesOutput("""
+div:not(.class):not([attr=5]), /* We should not catch this. */
+div:not(.class):not([attr]) /* Nor this. */ {
+  background: url(data:image/jpeg,asdfasdfsadf); /* Ignore this. */
+  background: -webkit-linear-gradient(left, red,
+                                      80% blah blee blar);
+  color: red;
+  display:block;
+}""", """
+- Colons (:) should have a space after them.
+    display:block;
+
+- Don't use data URIs in source files. Use grit instead.
+    background: url(data:image/jpeg,asdfasdfsadf);""")
+
+  def testCssFavorSingleQuotes(self):
+    self.VerifyContentsProducesOutput("""
+html[dir="rtl"] body,
+html[dir=ltr] body /* TODO(dbeam): Require '' around rtl in future? */ {
+  font-family: "Open Sans";
+<if expr="is_macosx">
+  blah: blee;
+</if>
+}""", """
+- Use single quotes (') instead of double quotes (") in strings.
+    html[dir="rtl"] body,
+    font-family: "Open Sans";""")
+
+  def testCssHexCouldBeShorter(self):
+    self.VerifyContentsProducesOutput("""
+#abc,
+#abc-,
+#abc-ghij,
+#abcdef-,
+#abcdef-ghij,
+#aaaaaa,
+#bbaacc {
+  background-color: #336699; /* Ignore short hex rule if not gray. */
+  color: #999999;
+  color: #666;
+}""", """
+- Use abbreviated hex (#rgb) when in form #rrggbb.
+    color: #999999; (replace with #999)
+
+- Use rgb() over #hex when not a shade of gray (like #333).
+    background-color: #336699; (replace with rgb(51, 102, 153))""")
+
+  def testCssUseMillisecondsForSmallTimes(self):
+    self.VerifyContentsProducesOutput("""
+.transition-0s /* This is gross but may happen. */ {
+  transform: one 0.2s;
+  transform: two .1s;
+  transform: tree 1s;
+  transform: four 300ms;
+}""", """
+- Use milliseconds for time measurements under 1 second.
+    transform: one 0.2s; (replace with 200ms)
+    transform: two .1s; (replace with 100ms)""")
+
+  def testCssNoDataUrisInSourceFiles(self):
+    self.VerifyContentsProducesOutput("""
+img {
+  background: url( data:image/jpeg,4\/\/350|\/|3|2 );
+}""", """
+- Don't use data URIs in source files. Use grit instead.
+    background: url( data:image/jpeg,4\/\/350|\/|3|2 );""")
+
+  def testCssNoMixinShims(self):
+    self.VerifyContentsProducesOutput("""
+:host {
+  --good-property: red;
+  --not-okay-mixin_-_not-okay-property: green;
+}""", """
+- Don't override custom properties created by Polymer's mixin shim. Set \
+mixins or documented custom properties directly.
+    --not-okay-mixin_-_not-okay-property: green;""")
+
+  def testCssNoQuotesInUrl(self):
+    self.VerifyContentsProducesOutput("""
+img {
+  background: url('chrome://resources/images/blah.jpg');
+  background: url("../../folder/hello.png");
+}""", """
+- Use single quotes (') instead of double quotes (") in strings.
+    background: url("../../folder/hello.png");
+
+- Don't use quotes in url().
+    background: url('chrome://resources/images/blah.jpg');
+    background: url("../../folder/hello.png");""")
+
+  def testCssOneRulePerLine(self):
+    self.VerifyContentsProducesOutput("""
+a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type,
+a:not([hidden]):not(.custom-appearance):not([version=1]):first-of-type ~
+    input[type='checkbox']:not([hidden]),
+div {
+  background: url(chrome://resources/BLAH);
+  rule: value; /* rule: value; */
+  rule: value; rule: value;
+}
+
+.remix {
+  --dj: {
+    spin: that;
+  };
+}
+""", """
+- One rule per line (what not to do: color: red; margin: 0;).
+    rule: value; rule: value;""")
+
+  def testCssOneSelectorPerLine(self):
+    self.VerifyContentsProducesOutput("""
+a,
+div,a,
+div,/* Hello! */ span,
+#id.class([dir=rtl):not(.class):any(a, b, d) {
+  rule: value;
+}
+
+a,
+div,a {
+  some-other: rule here;
+}""", """
+- One selector per line (what not to do: a, b {}).
+    div,a,
+    div, span,
+    div,a {""")
+
+  def testCssPseudoElementDoubleColon(self):
+    self.VerifyContentsProducesOutput("""
+a:href,
+br::after,
+::-webkit-scrollbar-thumb,
+a:not([empty]):hover:focus:active, /* shouldn't catch here and above */
+abbr:after,
+.tree-label:empty:after,
+b:before,
+:-WebKit-ScrollBar {
+  rule: value;
+}""", """
+- Pseudo-elements should use double colon (i.e. ::after).
+    :after (should be ::after)
+    :after (should be ::after)
+    :before (should be ::before)
+    :-WebKit-ScrollBar (should be ::-WebKit-ScrollBar)
+    """)
+
+  def testCssRgbIfNotGray(self):
+    self.VerifyContentsProducesOutput("""
+#abc,
+#aaa,
+#aabbcc {
+  background: -webkit-linear-gradient(left, from(#abc), to(#def));
+  color: #bad;
+  color: #bada55;
+}""", """
+- Use rgb() over #hex when not a shade of gray (like #333).
+    background: -webkit-linear-gradient(left, from(#abc), to(#def)); """
+"""(replace with rgb(170, 187, 204), rgb(221, 238, 255))
+    color: #bad; (replace with rgb(187, 170, 221))
+    color: #bada55; (replace with rgb(186, 218, 85))""")
+
+  def testWebkitBeforeOrAfter(self):
+    self.VerifyContentsProducesOutput("""
+.test {
+  -webkit-margin-before: 10px;
+  -webkit-margin-start: 20px;
+  -webkit-padding-after: 3px;
+  -webkit-padding-end: 5px;
+}
+""", """
+- Use *-top/bottom instead of -webkit-*-before/after.
+    -webkit-margin-before: 10px; (replace with margin-top)
+    -webkit-padding-after: 3px; (replace with padding-bottom)""")
+
+  def testCssZeroWidthLengths(self):
+    self.VerifyContentsProducesOutput("""
+@-webkit-keyframe anim {
+  0% { /* Ignore key frames */
+    width: 0px;
+  }
+  10% {
+    width: 10px;
+  }
+  50% { background-image: url(blah.svg); }
+  100% {
+    width: 100px;
+  }
+}
+
+#logo {
+  background-image: url(images/google_logo.png@2x);
+}
+
+body.alternate-logo #logo {
+  -webkit-mask-image: url(images/google_logo.png@2x);
+}
+
+/* http://crbug.com/359682 */
+#spinner-container #spinner {
+  -webkit-animation-duration: 1.0s;
+  background-image: url(images/google_logo0.svg);
+}
+
+.media-button.play > .state0.active,
+.media-button[state='0'] > .state0.normal /* blah */, /* blee */
+.media-button[state='0']:not(.disabled):hover > .state0.hover {
+  -webkit-animation: anim 0s;
+  -webkit-animation-duration: anim 0ms;
+  -webkit-transform: scale(0%);
+  background-position-x: 0em;
+  background-position-y: 0ex;
+  border-width: 0em;
+  color: hsl(0, 0%, 85%); /* Shouldn't trigger error. */
+  opacity: .0;
+  opacity: 0.0;
+  opacity: 0.;
+}
+
+@page {
+  border-width: 0mm;
+  height: 0cm;
+  width: 0in;
+}""", """
+- Use "0" for zero-width lengths (i.e. 0px -> 0)
+    width: 0px;
+    -webkit-transform: scale(0%);
+    background-position-x: 0em;
+    background-position-y: 0ex;
+    border-width: 0em;
+    opacity: .0;
+    opacity: 0.0;
+    opacity: 0.;
+    border-width: 0mm;
+    height: 0cm;
+    width: 0in;
+""")
+
+  def testInlineStyleInHtml(self):
+    self.VerifyContentsProducesOutput("""<!doctype html>
+<html>
+<head>
+  <!-- Don't warn about problems outside of style tags
+    html,
+    body {
+      margin: 0;
+      height: 100%;
+    }
+  -->
+  <style>
+    body {
+      flex-direction:column;
+    }
+  </style>
+</head>
+</html>""", """
+- Colons (:) should have a space after them.
+    flex-direction:column;
+""", filename='test.html')
+
+  def testInlineStyleInHtmlWithIncludes(self):
+    self.VerifyContentsProducesOutput("""<!doctype html>
+<html>
+  <style include="fake-shared-css other-shared-css">
+    body {
+      flex-direction:column;
+    }
+  </style>
+</head>
+</html>""", """
+- Colons (:) should have a space after them.
+    flex-direction:column;
+""", filename='test.html')
+
+  def testInlineSTyleInHtmlWithTagsInComments(self):
+    self.VerifyContentsProducesOutput("""<!doctype html>
+<html>
+  <style>
+    body {
+      /* You better ignore the <tag> in this comment! */
+      flex-direction:column;
+    }
+  </style>
+</head>
+</html>""", """
+- Colons (:) should have a space after them.
+    flex-direction:column;
+""", filename='test.html')
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/web_dev_style/html_checker.py b/tools/web_dev_style/html_checker.py
new file mode 100644
index 0000000..f646b9d
--- /dev/null
+++ b/tools/web_dev_style/html_checker.py
@@ -0,0 +1,116 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Presubmit for Chromium HTML resources. See chrome/browser/PRESUBMIT.py.
+"""
+
+import regex_check
+
+
+class HtmlChecker(object):
+  def __init__(self, input_api, output_api, file_filter=None):
+    self.input_api = input_api
+    self.output_api = output_api
+    self.file_filter = file_filter
+
+  def ClassesUseDashFormCheck(self, line_number, line):
+    regex = self.input_api.re.compile("""
+        (?:^|\s)                    # start of line or whitespace
+        (class="[^"]*[A-Z_][^"]*")  # class contains caps or '_'
+        """,
+        self.input_api.re.VERBOSE)
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        "Classes should use dash-form.")
+
+  def DoNotCloseSingleTagsCheck(self, line_number, line):
+    regex = r"(/>)"
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        "Do not close single tags.")
+
+  def DoNotUseBrElementCheck(self, line_number, line):
+    regex = r"(<br)"
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        "Do not use <br>; place blocking elements (<div>) as appropriate.")
+
+  def DoNotUseInputTypeButtonCheck(self, line_number, line):
+    regex = self.input_api.re.compile("""
+        (<input [^>]*  # "<input " followed by anything but ">"
+        type="button"  # type="button"
+        [^>]*>)        # anything but ">" then ">"
+        """,
+        self.input_api.re.VERBOSE)
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        'Use the button element instead of <input type="button">')
+
+  def DoNotUseSingleQuotesCheck(self, line_number, line):
+    regex = self.input_api.re.compile("""
+        <\S+                           # The tag name.
+        (?:\s+\S+\$?="[^"]*"|\s+\S+)*  # Correctly quoted or non-value props.
+        \s+(\S+\$?='[^']*')            # Find incorrectly quoted (foo='bar').
+        [^>]*>                         # To the end of the tag.
+        """,
+        self.input_api.re.MULTILINE | self.input_api.re.VERBOSE)
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        'Use double quotes rather than single quotes in HTML properties')
+
+  def I18nContentJavaScriptCaseCheck(self, line_number, line):
+    regex = self.input_api.re.compile("""
+        (?:^|\s)                      # start of line or whitespace
+        i18n-content="                # i18n-content="
+        ([A-Z][^"]*|[^"]*[-_][^"]*)"  # starts with caps or contains '-' or '_'
+        """,
+        self.input_api.re.VERBOSE)
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        "For i18n-content use javaScriptCase.")
+
+  def LabelCheck(self, line_number, line):
+    regex = self.input_api.re.compile("""
+        (?:^|\s)     # start of line or whitespace
+        <label[^>]+? # <label tag
+        (for=)       # for=
+        """,
+        self.input_api.re.VERBOSE)
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        "Avoid 'for' attribute on <label>. Place the input within the <label>, "
+        "or use aria-labelledby for <select>.")
+
+  def QuotePolymerBindings(self, line_number, line):
+    regex = self.input_api.re.compile(r"=(\[\[|\{\{)")
+    return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
+        'Please use quotes around Polymer bindings (i.e. attr="[[prop]]")')
+
+  def RunChecks(self):
+    """Check for violations of the Chromium web development style guide. See
+       https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md
+    """
+    results = []
+
+    affected_files = self.input_api.AffectedFiles(file_filter=self.file_filter,
+                                                  include_deletes=False)
+
+    for f in affected_files:
+      if not f.LocalPath().endswith('.html'):
+        continue
+
+      errors = []
+
+      for line_number, line in f.ChangedContents():
+        errors.extend(filter(None, [
+            self.ClassesUseDashFormCheck(line_number, line),
+            self.DoNotCloseSingleTagsCheck(line_number, line),
+            self.DoNotUseBrElementCheck(line_number, line),
+            self.DoNotUseInputTypeButtonCheck(line_number, line),
+            self.I18nContentJavaScriptCaseCheck(line_number, line),
+            self.LabelCheck(line_number, line),
+            self.QuotePolymerBindings(line_number, line),
+        ]))
+
+      if errors:
+        abs_local_path = f.AbsoluteLocalPath()
+        file_indicator = 'Found HTML style issues in %s' % abs_local_path
+        prompt_msg = file_indicator + '\n\n' + '\n'.join(errors) + '\n'
+        results.append(self.output_api.PresubmitPromptWarning(prompt_msg))
+
+    return results
diff --git a/tools/web_dev_style/html_checker_test.py b/tools/web_dev_style/html_checker_test.py
new file mode 100755
index 0000000..f059f7d
--- /dev/null
+++ b/tools/web_dev_style/html_checker_test.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import html_checker
+from os import path as os_path
+import re
+from sys import path as sys_path
+import test_util
+import unittest
+
+_HERE = os_path.dirname(os_path.abspath(__file__))
+sys_path.append(os_path.join(_HERE, '..', '..', 'build'))
+
+import find_depot_tools  # pylint: disable=W0611
+from testing_support.super_mox import SuperMoxTestBase
+
+
+class HtmlCheckerTest(SuperMoxTestBase):
+  def setUp(self):
+    SuperMoxTestBase.setUp(self)
+
+    input_api = self.mox.CreateMockAnything()
+    input_api.re = re
+    output_api = self.mox.CreateMockAnything()
+    self.checker = html_checker.HtmlChecker(input_api, output_api)
+
+  def ShouldFailCheck(self, line, checker):
+    """Checks that the |checker| flags |line| as a style error."""
+    error = checker(1, line)
+    self.assertNotEqual('', error, 'Should be flagged as style error: ' + line)
+    highlight = test_util.GetHighlight(line, error).strip()
+
+  def ShouldPassCheck(self, line, checker):
+    """Checks that the |checker| doesn't flag |line| as a style error."""
+    error = checker(1, line)
+    self.assertEqual('', error, 'Should not be flagged as style error: ' + line)
+
+  def testClassesUseDashFormCheckFails(self):
+    lines = [
+      ' <a class="Foo-bar" href="classBar"> ',
+      '<b class="foo-Bar"> ',
+      '<i class="foo_bar" >',
+      ' <hr class="fooBar"> ',
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.ClassesUseDashFormCheck)
+
+  def testClassesUseDashFormCheckPasses(self):
+    lines = [
+      ' class="abc" ',
+      'class="foo-bar"',
+      '<div class="foo-bar" id="classBar"',
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.ClassesUseDashFormCheck)
+
+  def testSingleQuoteCheckFails(self):
+    lines = [
+      """ <a href='classBar'> """,
+      """<a foo$="bar" href$='classBar'>""",
+      """<a foo="bar" less="more" href='classBar' kittens="cats">""",
+      """<a cats href='classBar' dogs>""",
+      """<a cats\n href='classBat\nclassBaz'\n dogs>""",
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.DoNotUseSingleQuotesCheck)
+
+  def testSingleQuoteCheckPasses(self):
+    lines = [
+      """<b id="super-valid">SO VALID!</b>""",
+      """<a text$="i ain't got invalid quotes">i don't</a>""",
+      """<span>[[i18n('blah')]]</span> """,
+      """<a cats href="classBar" dogs>""",
+      """<a cats\n href="classBar"\n dogs>""",
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.DoNotUseSingleQuotesCheck)
+
+  def testDoNotCloseSingleTagsCheckFails(self):
+    lines = [
+      "<input/>",
+      ' <input id="a" /> ',
+      "<div/>",
+      "<br/>",
+      "<br />",
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.DoNotCloseSingleTagsCheck)
+
+  def testDoNotCloseSingleTagsCheckPasses(self):
+    lines = [
+      "<input>",
+      "<link>",
+      "<div></div>",
+      '<input text="/">',
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.DoNotCloseSingleTagsCheck)
+
+  def testDoNotUseBrElementCheckFails(self):
+    lines = [
+      " <br>",
+      "<br  >  ",
+      "<br\>",
+      '<br name="a">',
+    ]
+    for line in lines:
+      self.ShouldFailCheck(
+          line, self.checker.DoNotUseBrElementCheck)
+
+  def testDoNotUseBrElementCheckPasses(self):
+    lines = [
+      "br",
+      "br>",
+      "give me a break"
+    ]
+    for line in lines:
+      self.ShouldPassCheck(
+          line, self.checker.DoNotUseBrElementCheck)
+
+  def testDoNotUseInputTypeButtonCheckFails(self):
+    lines = [
+      '<input type="button">',
+      ' <input id="a" type="button" >',
+      '<input type="button" id="a"> ',
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.DoNotUseInputTypeButtonCheck)
+
+  def testDoNotUseInputTypeButtonCheckPasses(self):
+    lines = [
+      "<input>",
+      '<input type="text">',
+      '<input type="result">',
+      '<input type="submit">',
+      "<button>",
+      '<button type="button">',
+      '<button type="reset">',
+      '<button type="submit">',
+
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.DoNotUseInputTypeButtonCheck)
+
+  def testI18nContentJavaScriptCaseCheckFails(self):
+    lines = [
+      ' i18n-content="foo-bar" ',
+      'i18n-content="foo_bar"',
+      'i18n-content="FooBar"',
+      'i18n-content="_foo"',
+      'i18n-content="foo_"',
+      'i18n-content="-foo"',
+      'i18n-content="foo-"',
+      'i18n-content="Foo"',
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.I18nContentJavaScriptCaseCheck)
+
+  def testI18nContentJavaScriptCaseCheckPasses(self):
+    lines = [
+      ' i18n-content="abc" ',
+      'i18n-content="fooBar"',
+      'i18n-content="validName" attr="invalidName_"',
+      '<div i18n-content="exampleTitle"',
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.I18nContentJavaScriptCaseCheck)
+
+  def testLabelCheckFails(self):
+    lines = [
+      ' <label for="abc"',
+      " <label for=    ",
+      " <label\tfor=    ",
+      ' <label\n blah="1" blee="3"\n for="goop"',
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.LabelCheck)
+
+  def testLabelCheckPasses(self):
+    lines = [
+      ' my-for="abc" ',
+      ' myfor="abc" ',
+      " <for",
+      ' <paper-tooltip for="id-name"',
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.LabelCheck)
+
+  def testQuotePolymerBindingsFails(self):
+    lines = [
+      "<a href=[[blah]]>",
+      "<div class$=[[class_]]>",
+      "<settings-checkbox prefs={{prefs}}",
+      "<paper-button actionable$=[[isActionable_(a,b)]]>",
+    ]
+    for line in lines:
+      self.ShouldFailCheck(line, self.checker.QuotePolymerBindings)
+
+  def testQuotePolymerBindingsPasses(self):
+    lines = [
+      '<a href="[[blah]]">',
+      '<span id="blah">[[text]]</span>',
+      '<setting-checkbox prefs="{{prefs}}">',
+      '<paper-input tab-index="[[tabIndex_]]">',
+      '<div style="font: [[getFont_(item)]]">',
+    ]
+    for line in lines:
+      self.ShouldPassCheck(line, self.checker.QuotePolymerBindings)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/web_dev_style/js_checker.py b/tools/web_dev_style/js_checker.py
new file mode 100644
index 0000000..a42a1a22
--- /dev/null
+++ b/tools/web_dev_style/js_checker.py
@@ -0,0 +1,128 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit script for Chromium JS resources.
+
+See chrome/browser/PRESUBMIT.py
+"""
+
+import regex_check
+
+
+class JSChecker(object):
+  def __init__(self, input_api, output_api, file_filter=None):
+    self.input_api = input_api
+    self.output_api = output_api
+    self.file_filter = file_filter
+
+  def RegexCheck(self, line_number, line, regex, message):
+    return regex_check.RegexCheck(
+        self.input_api.re, line_number, line, regex, message)
+
+  def ChromeSendCheck(self, i, line):
+    """Checks for a particular misuse of 'chrome.send'."""
+    return self.RegexCheck(i, line, r"chrome\.send\('[^']+'\s*(, \[\])\)",
+        'Passing an empty array to chrome.send is unnecessary')
+
+  def CommentIfAndIncludeCheck(self, line_number, line):
+    return self.RegexCheck(line_number, line, r'(?<!\/\/ )(<if|<include) ',
+        '<if> or <include> should be in a single line comment with a space ' +
+        'after the slashes. Examples:\n' +
+        '    // <include src="...">\n' +
+        '    // <if expr="chromeos">\n' +
+        '    // </if>\n')
+
+  def ConstCheck(self, i, line):
+    """Check for use of the 'const' keyword."""
+    if self.input_api.re.search(r'\*\s+@const', line):
+      # Probably a JsDoc line
+      return ''
+
+    return self.RegexCheck(i, line, r'(?:^|\s|\()(const)\s',
+        'Use /** @const */ var varName; instead of const varName;')
+
+  def EndJsDocCommentCheck(self, i, line):
+    msg = 'End JSDoc comments with */ instead of **/'
+    def _check(regex):
+      return self.RegexCheck(i, line, regex, msg)
+    return _check(r'^\s*(\*\*/)\s*$') or _check(r'/\*\* @[a-zA-Z]+.* (\*\*/)')
+
+  def ExtraDotInGenericCheck(self, i, line):
+    return self.RegexCheck(i, line, r"((?:Array|Object|Promise)\.<)",
+        "Don't use a dot after generics (Object.<T> should be Object<T>).")
+
+  def GetElementByIdCheck(self, i, line):
+    """Checks for use of 'document.getElementById' instead of '$'."""
+    return self.RegexCheck(i, line, r"(document\.getElementById)\('",
+        "Use $('id') or getSVGElement('id') from chrome://resources/js/util.js "
+        "instead of document.getElementById('id')")
+
+  def InheritDocCheck(self, i, line):
+    """Checks for use of '@inheritDoc' instead of '@override'."""
+    return self.RegexCheck(i, line, r"\* (@inheritDoc)",
+        "@inheritDoc is deprecated, use @override instead")
+
+  def PolymerLocalIdCheck(self, i, line):
+    """Checks for use of element.$.localId."""
+    return self.RegexCheck(i, line, r"(?<!this)(\.\$)[\[\.]",
+        "Please only use this.$.localId, not element.$.localId")
+
+  def WrapperTypeCheck(self, i, line):
+    """Check for wrappers (new String()) instead of builtins (string)."""
+    return self.RegexCheck(i, line,
+        r"(?:/\*)?\*.*?@(?:param|return|type) ?"     # /** @param/@return/@type
+        r"{[^}]*\b(String|Boolean|Number)\b[^}]*}",  # {(Boolean|Number|String)}
+        "Don't use wrapper types (i.e. new String() or @type {String})")
+
+  def VarNameCheck(self, i, line):
+    """See the style guide. http://goo.gl/eQiXVW"""
+    return self.RegexCheck(i, line,
+        r"var (?!g_\w+)(_?[a-z][a-zA-Z]*[_$][\w_$]*)(?<! \$)",
+        "Please use var namesLikeThis <https://goo.gl/eQiXVW>")
+
+  def _GetErrorHighlight(self, start, length):
+    """Takes a start position and a length, and produces a row of '^'s to
+       highlight the corresponding part of a string.
+    """
+    return start * ' ' + length * '^'
+
+  def RunChecks(self):
+    """Check for violations of the Chromium JavaScript style guide. See
+       https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md#JavaScript
+    """
+    results = []
+
+    affected_files = self.input_api.AffectedFiles(file_filter=self.file_filter,
+                                                  include_deletes=False)
+    affected_js_files = filter(lambda f: f.LocalPath().endswith('.js'),
+                               affected_files)
+    for f in affected_js_files:
+      error_lines = []
+
+      for i, line in enumerate(f.NewContents(), start=1):
+        error_lines += filter(None, [
+            self.ChromeSendCheck(i, line),
+            self.CommentIfAndIncludeCheck(i, line),
+            self.ConstCheck(i, line),
+            self.GetElementByIdCheck(i, line),
+            self.EndJsDocCommentCheck(i, line),
+            self.ExtraDotInGenericCheck(i, line),
+            self.InheritDocCheck(i, line),
+            self.PolymerLocalIdCheck(i, line),
+            self.WrapperTypeCheck(i, line),
+            self.VarNameCheck(i, line),
+        ])
+
+      if error_lines:
+        error_lines = [
+            'Found JavaScript style violations in %s:' %
+            f.LocalPath()] + error_lines
+        results.append(self.output_api.PresubmitError('\n'.join(error_lines)))
+
+    if results:
+      results.append(self.output_api.PresubmitNotifyResult(
+          'See the JavaScript style guide at '
+          'https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md#JavaScript'))
+
+    return results
diff --git a/tools/web_dev_style/js_checker_test.py b/tools/web_dev_style/js_checker_test.py
new file mode 100755
index 0000000..72f9954
--- /dev/null
+++ b/tools/web_dev_style/js_checker_test.py
@@ -0,0 +1,400 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import js_checker
+from os import path as os_path
+import re
+from sys import path as sys_path
+import test_util
+import unittest
+
+_HERE = os_path.dirname(os_path.abspath(__file__))
+sys_path.append(os_path.join(_HERE, '..', '..', 'build'))
+
+import find_depot_tools  # pylint: disable=W0611
+from testing_support.super_mox import SuperMoxTestBase
+
+
+class JsCheckerTest(SuperMoxTestBase):
+  def setUp(self):
+    SuperMoxTestBase.setUp(self)
+
+    input_api = self.mox.CreateMockAnything()
+    input_api.re = re
+    output_api = self.mox.CreateMockAnything()
+    self.checker = js_checker.JSChecker(input_api, output_api)
+
+  def ShouldFailCommentCheck(self, line):
+    """Checks that uncommented '<if>' and '<include>' are a style error."""
+    error = self.checker.CommentIfAndIncludeCheck(1, line)
+    self.assertNotEqual('', error, 'Should be flagged as style error: ' + line)
+    highlight = test_util.GetHighlight(line, error).strip()
+    self.assertTrue(highlight.startswith(('<if', '<include')))
+
+  def ShouldPassCommentCheck(self, line):
+    """Checks that commented '<if>' and '<include>' are allowed."""
+    self.assertEqual('', self.checker.CommentIfAndIncludeCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testCommentFails(self):
+    lines = [
+        '<include src="blah.js">',
+        # Currently, only "// " is accepted (not just "//" or "//\s+") as Python
+        # can't do variable-length lookbehind.
+        '//<include src="blah.js">',
+        '//  <include src="blah.js">',
+        '             <include src="blee.js">',
+        '  <if expr="chromeos">',
+        '<if expr="lang == \'de\'">',
+        '//<if expr="bitness == 64">',
+    ]
+    for line in lines:
+      self.ShouldFailCommentCheck(line)
+
+  def testCommentPasses(self):
+    lines = [
+        '// <include src="assert.js">',
+        '             // <include src="util.js"/>',
+        '// <if expr="chromeos">',
+        '           // <if expr="not chromeos">',
+        "   '<iframe src=blah.html>';",
+    ]
+    for line in lines:
+      self.ShouldPassCommentCheck(line)
+
+  def ShouldFailConstCheck(self, line):
+    """Checks that the 'const' checker flags |line| as a style error."""
+    error = self.checker.ConstCheck(1, line)
+    self.assertNotEqual('', error,
+        'Should be flagged as style error: ' + line)
+    self.assertEqual(test_util.GetHighlight(line, error), 'const')
+
+  def ShouldPassConstCheck(self, line):
+    """Checks that the 'const' checker doesn't flag |line| as a style error."""
+    self.assertEqual('', self.checker.ConstCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testConstFails(self):
+    lines = [
+        "const foo = 'bar';",
+        "    const bar = 'foo';",
+
+        # Trying to use |const| as a variable name
+        "var const = 0;",
+
+        "var x = 5; const y = 6;",
+        "for (var i=0, const e=10; i<e; i++) {",
+        "for (const x=0; x<foo; i++) {",
+        "while (const x = 7) {",
+    ]
+    for line in lines:
+      self.ShouldFailConstCheck(line)
+
+  def testConstPasses(self):
+    lines = [
+        # sanity check
+        "var foo = 'bar'",
+
+        # @const JsDoc tag
+        "/** @const */ var SEVEN = 7;",
+
+        # @const tag in multi-line comment
+        " * @const",
+        "   * @const",
+
+        # @constructor tag in multi-line comment
+        " * @constructor",
+        "   * @constructor",
+
+        # words containing 'const'
+        "if (foo.constructor) {",
+        "var deconstruction = 'something';",
+        "var madeUpWordconst = 10;",
+
+        # Strings containing the word |const|
+        "var str = 'const at the beginning';",
+        "var str = 'At the end: const';",
+
+        # doing this one with regex is probably not practical
+        #"var str = 'a const in the middle';",
+    ]
+    for line in lines:
+      self.ShouldPassConstCheck(line)
+
+  def ShouldFailChromeSendCheck(self, line):
+    """Checks that the 'chrome.send' checker flags |line| as a style error."""
+    error = self.checker.ChromeSendCheck(1, line)
+    self.assertNotEqual('', error,
+        'Should be flagged as style error: ' + line)
+    self.assertEqual(test_util.GetHighlight(line, error), ', []')
+
+  def ShouldPassChromeSendCheck(self, line):
+    """Checks that the 'chrome.send' checker doesn't flag |line| as a style
+       error.
+    """
+    self.assertEqual('', self.checker.ChromeSendCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testChromeSendFails(self):
+    lines = [
+        "chrome.send('message', []);",
+        "  chrome.send('message', []);",
+    ]
+    for line in lines:
+      self.ShouldFailChromeSendCheck(line)
+
+  def testChromeSendPasses(self):
+    lines = [
+        "chrome.send('message', constructArgs('foo', []));",
+        "  chrome.send('message', constructArgs('foo', []));",
+        "chrome.send('message', constructArgs([]));",
+        "  chrome.send('message', constructArgs([]));",
+    ]
+    for line in lines:
+      self.ShouldPassChromeSendCheck(line)
+
+  def ShouldFailEndJsDocCommentCheck(self, line):
+    """Checks that the **/ checker flags |line| as a style error."""
+    error = self.checker.EndJsDocCommentCheck(1, line)
+    self.assertNotEqual('', error,
+        'Should be flagged as style error: ' + line)
+    self.assertEqual(test_util.GetHighlight(line, error), '**/')
+
+  def ShouldPassEndJsDocCommentCheck(self, line):
+    """Checks that the **/ checker doesn't flag |line| as a style error."""
+    self.assertEqual('', self.checker.EndJsDocCommentCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testEndJsDocCommentFails(self):
+    lines = [
+        "/** @override **/",
+        "/** @type {number} @const **/",
+        "  **/",
+        "**/  ",
+    ]
+    for line in lines:
+      self.ShouldFailEndJsDocCommentCheck(line)
+
+  def testEndJsDocCommentPasses(self):
+    lines = [
+        "/***************/",  # visual separators
+        "  */",  # valid JSDoc comment ends
+        "*/  ",
+        "/**/",  # funky multi-line comment enders
+        "/** @override */",  # legit JSDoc one-liners
+    ]
+    for line in lines:
+      self.ShouldPassEndJsDocCommentCheck(line)
+
+  def ShouldFailExtraDotInGenericCheck(self, line):
+    """Checks that Array.< or Object.< is flagged as a style nit."""
+    error = self.checker.ExtraDotInGenericCheck(1, line)
+    self.assertNotEqual('', error)
+    self.assertTrue(test_util.GetHighlight(line, error).endswith(".<"))
+
+  def testExtraDotInGenericFails(self):
+    lines = [
+        "/** @private {!Array.<!Frobber>} */",
+        "var a = /** @type {Object.<number>} */({});",
+        "* @return {!Promise.<Change>}"
+    ]
+    for line in lines:
+      self.ShouldFailExtraDotInGenericCheck(line)
+
+  def ShouldFailGetElementByIdCheck(self, line):
+    """Checks that the 'getElementById' checker flags |line| as a style
+       error.
+    """
+    error = self.checker.GetElementByIdCheck(1, line)
+    self.assertNotEqual('', error,
+        'Should be flagged as style error: ' + line)
+    self.assertEqual(test_util.GetHighlight(line, error),
+                     'document.getElementById')
+
+  def ShouldPassGetElementByIdCheck(self, line):
+    """Checks that the 'getElementById' checker doesn't flag |line| as a style
+       error.
+    """
+    self.assertEqual('', self.checker.GetElementByIdCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testGetElementByIdFails(self):
+    lines = [
+        "document.getElementById('foo');",
+        "  document.getElementById('foo');",
+        "var x = document.getElementById('foo');",
+        "if (document.getElementById('foo').hidden) {",
+    ]
+    for line in lines:
+      self.ShouldFailGetElementByIdCheck(line)
+
+  def testGetElementByIdPasses(self):
+    lines = [
+        "elem.ownerDocument.getElementById('foo');",
+        "  elem.ownerDocument.getElementById('foo');",
+        "var x = elem.ownerDocument.getElementById('foo');",
+        "if (elem.ownerDocument.getElementById('foo').hidden) {",
+        "doc.getElementById('foo');",
+        "  doc.getElementById('foo');",
+        "cr.doc.getElementById('foo');",
+        "  cr.doc.getElementById('foo');",
+        "var x = doc.getElementById('foo');",
+        "if (doc.getElementById('foo').hidden) {",
+    ]
+    for line in lines:
+      self.ShouldPassGetElementByIdCheck(line)
+
+  def ShouldFailInheritDocCheck(self, line):
+    """Checks that the '@inheritDoc' checker flags |line| as a style error."""
+    error = self.checker.InheritDocCheck(1, line)
+    self.assertNotEqual('', error,
+        msg='Should be flagged as style error: ' + line)
+    self.assertEqual(test_util.GetHighlight(line, error), '@inheritDoc')
+
+  def ShouldPassInheritDocCheck(self, line):
+    """Checks that the '@inheritDoc' checker doesn't flag |line| as a style
+       error.
+    """
+    self.assertEqual('', self.checker.InheritDocCheck(1, line),
+        msg='Should not be flagged as style error: ' + line)
+
+  def testInheritDocFails(self):
+    lines = [
+        " /** @inheritDoc */",
+        "   * @inheritDoc",
+    ]
+    for line in lines:
+      self.ShouldFailInheritDocCheck(line)
+
+  def testInheritDocPasses(self):
+    lines = [
+        "And then I said, but I won't @inheritDoc! Hahaha!",
+        " If your dad's a doctor, do you inheritDoc?",
+        "  What's up, inherit doc?",
+        "   this.inheritDoc(someDoc)",
+    ]
+    for line in lines:
+      self.ShouldPassInheritDocCheck(line)
+
+  def ShouldFailPolymerLocalIdCheck(self, line):
+    """Checks that element.$.localId check marks |line| as a style error."""
+    error = self.checker.PolymerLocalIdCheck(1, line)
+    self.assertNotEqual('', error,
+        msg='Should be flagged as a style error: ' + line)
+    self.assertTrue('.$' in test_util.GetHighlight(line, error))
+
+  def ShouldPassPolymerLocalIdCheck(self, line):
+    """Checks that element.$.localId check doesn't mark |line| as a style
+       error."""
+    self.assertEqual('', self.checker.PolymerLocalIdCheck(1, line),
+        msg='Should not be flagged as a style error: ' + line)
+
+  def testPolymerLocalIdFails(self):
+    lines = [
+        "cat.$.dog",
+        "thing1.$.thing2",
+        "element.$.localId",
+        "element.$['fancy-hyphenated-id']",
+    ]
+    for line in lines:
+      self.ShouldFailPolymerLocalIdCheck(line)
+
+  def testPolymerLocalIdPasses(self):
+    lines = [
+        "this.$.id",
+        "this.$.localId",
+        "this.$['fancy-id']",
+    ]
+    for line in lines:
+      self.ShouldPassPolymerLocalIdCheck(line)
+
+  def ShouldFailWrapperTypeCheck(self, line):
+    """Checks that the use of wrapper types (i.e. new Number(), @type {Number})
+       is a style error.
+    """
+    error = self.checker.WrapperTypeCheck(1, line)
+    self.assertNotEqual('', error,
+        msg='Should be flagged as style error: ' + line)
+    highlight = test_util.GetHighlight(line, error)
+    self.assertTrue(highlight in ('Boolean', 'Number', 'String'))
+
+  def ShouldPassWrapperTypeCheck(self, line):
+    """Checks that the wrapper type checker doesn't flag |line| as a style
+       error.
+    """
+    self.assertEqual('', self.checker.WrapperTypeCheck(1, line),
+        msg='Should not be flagged as style error: ' + line)
+
+  def testWrapperTypePasses(self):
+    lines = [
+        "/** @param {!ComplexType} */",
+        "  * @type {Object}",
+        "   * @param {Function=} opt_callback",
+        "    * @param {} num Number of things to add to {blah}.",
+        "   *  @return {!print_preview.PageNumberSet}",
+        " /* @returns {Number} */",  # Should be /** @return {Number} */
+        "* @param {!LocalStrings}"
+        " Your type of Boolean is false!",
+        "  Then I parameterized a Number from my friend!",
+        "   A String of Pearls",
+        "    types.params.aBoolean.typeString(someNumber)",
+    ]
+    for line in lines:
+      self.ShouldPassWrapperTypeCheck(line)
+
+  def testWrapperTypeFails(self):
+    lines = [
+        "  /**@type {String}*/(string)",
+        "   * @param{Number=} opt_blah A number",
+        "/** @private @return {!Boolean} */",
+        " * @param {number|String}",
+    ]
+    for line in lines:
+      self.ShouldFailWrapperTypeCheck(line)
+
+  def ShouldFailVarNameCheck(self, line):
+    """Checks that var unix_hacker, $dollar are style errors."""
+    error = self.checker.VarNameCheck(1, line)
+    self.assertNotEqual('', error,
+        msg='Should be flagged as style error: ' + line)
+    highlight = test_util.GetHighlight(line, error)
+    self.assertFalse('var ' in highlight);
+
+  def ShouldPassVarNameCheck(self, line):
+    """Checks that variableNamesLikeThis aren't style errors."""
+    self.assertEqual('', self.checker.VarNameCheck(1, line),
+        msg='Should not be flagged as style error: ' + line)
+
+  def testVarNameFails(self):
+    lines = [
+        "var private_;",
+        "var hostName_ = 'https://google.com';",
+        " var _super_private",
+        "  var unix_hacker = someFunc();",
+    ]
+    for line in lines:
+      self.ShouldFailVarNameCheck(line)
+
+  def testVarNamePasses(self):
+    lines = [
+        "  var namesLikeThis = [];",
+        " for (var i = 0; i < 10; ++i) { ",
+        "for (var i in obj) {",
+        " var one, two, three;",
+        "  var magnumPI = {};",
+        " var g_browser = 'da browzer';",
+        "/** @const */ var Bla = options.Bla;",  # goog.scope() replacement.
+        " var $ = function() {",                 # For legacy reasons.
+        "  var StudlyCaps = cr.define('bla')",   # Classes.
+        " var SCARE_SMALL_CHILDREN = [",         # TODO(dbeam): add @const in
+                                                 # front of all these vars like
+        "/** @const */ CONST_VAR = 1;",          # this line has (<--).
+    ]
+    for line in lines:
+      self.ShouldPassVarNameCheck(line)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/web_dev_style/presubmit_support.py b/tools/web_dev_style/presubmit_support.py
new file mode 100644
index 0000000..09da594
--- /dev/null
+++ b/tools/web_dev_style/presubmit_support.py
@@ -0,0 +1,25 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import css_checker
+import html_checker
+import js_checker
+import resource_checker
+
+
+def CheckStyle(input_api, output_api, file_filter=lambda f: True):
+  apis = input_api, output_api
+  is_resource = lambda f: f.LocalPath().endswith(('.html', '.css', '.js'))
+  wrapped_filter = lambda f: file_filter(f) and is_resource(f)
+  checkers = [
+      css_checker.CSSChecker(*apis, file_filter=wrapped_filter),
+      html_checker.HtmlChecker(*apis, file_filter=wrapped_filter),
+      js_checker.JSChecker(*apis, file_filter=wrapped_filter),
+      resource_checker.ResourceChecker(*apis, file_filter=wrapped_filter),
+  ]
+  results = []
+  for checker in checkers:
+    results.extend(checker.RunChecks())
+  return results
diff --git a/tools/web_dev_style/regex_check.py b/tools/web_dev_style/regex_check.py
new file mode 100644
index 0000000..d505e42
--- /dev/null
+++ b/tools/web_dev_style/regex_check.py
@@ -0,0 +1,28 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def RegexCheck(re, line_number, line, regex, msg):
+  """Searches for |regex| in |line| to check for a particular style
+     violation, returning a message like the one below if the regex matches.
+     The |regex| must have exactly one capturing group so that the relevant
+     part of |line| can be highlighted. If more groups are needed, use
+     "(?:...)" to make a non-capturing group. Sample message:
+
+       line 6: Use var instead of const.
+           const foo = bar();
+           ^^^^^
+  """
+
+  def _highlight(match):
+    """Takes a start position and a length, and produces a row of '^'s to
+       highlight the corresponding part of a string.
+    """
+    return match.start(1) * ' ' + (match.end(1) - match.start(1)) * '^'
+
+  match = re.search(regex, line)
+  if match:
+    assert len(match.groups()) == 1
+    return '  line %d: %s\n%s\n%s' % (line_number, msg, line, _highlight(match))
+  return ''
diff --git a/tools/web_dev_style/resource_checker.py b/tools/web_dev_style/resource_checker.py
new file mode 100644
index 0000000..69b8185
--- /dev/null
+++ b/tools/web_dev_style/resource_checker.py
@@ -0,0 +1,45 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Presubmit for Chromium HTML/CSS/JS resources. See chrome/browser/PRESUBMIT.py.
+"""
+
+import regex_check
+
+
+class ResourceChecker(object):
+  def __init__(self, input_api, output_api, file_filter=None):
+    self.input_api = input_api
+    self.output_api = output_api
+    self.file_filter = file_filter
+
+  def IncludeCheck(self, line_number, line):
+    return regex_check.RegexCheck(self.input_api.re, line_number, line,
+        "(</include>|<include.*/>)", "Closing <include> tags is unnecessary.")
+
+  def RunChecks(self):
+    """Check for violations of the Chromium web development style guide. See
+       https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/web.md
+    """
+    results = []
+
+    affected_files = self.input_api.AffectedFiles(file_filter=self.file_filter,
+                                                  include_deletes=False)
+
+    for f in affected_files:
+      errors = []
+
+      for line_number, line in enumerate(f.NewContents(), start=1):
+        error = self.IncludeCheck(line_number, line)
+        if error:
+          errors.append(error)
+
+      if errors:
+        abs_local_path = f.AbsoluteLocalPath()
+        file_indicator = 'Found resources style issues in %s' % abs_local_path
+        prompt_msg = file_indicator + '\n\n' + '\n'.join(errors) + '\n'
+        results.append(self.output_api.PresubmitPromptWarning(prompt_msg))
+
+    return results
diff --git a/tools/web_dev_style/resource_checker_test.py b/tools/web_dev_style/resource_checker_test.py
new file mode 100755
index 0000000..0f0abd9
--- /dev/null
+++ b/tools/web_dev_style/resource_checker_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from os import path as os_path
+import re
+import resource_checker
+from sys import path as sys_path
+import test_util
+import unittest
+
+_HERE = os_path.dirname(os_path.abspath(__file__))
+sys_path.append(os_path.join(_HERE, '..', '..', 'build'))
+
+import find_depot_tools  # pylint: disable=W0611
+from testing_support.super_mox import SuperMoxTestBase
+
+
+class ResourceCheckerTest(SuperMoxTestBase):
+  def setUp(self):
+    SuperMoxTestBase.setUp(self)
+
+    input_api = self.mox.CreateMockAnything()
+    input_api.re = re
+    output_api = self.mox.CreateMockAnything()
+    self.checker = resource_checker.ResourceChecker(input_api, output_api)
+
+  def ShouldFailIncludeCheck(self, line):
+    """Checks that the '</include>' checker flags |line| as a style error."""
+    error = self.checker.IncludeCheck(1, line)
+    self.assertNotEqual('', error,
+        'Should be flagged as style error: ' + line)
+    highlight = test_util.GetHighlight(line, error).strip()
+    self.assertTrue('include' in highlight and highlight[0] == '<')
+
+  def ShouldPassIncludeCheck(self, line):
+    """Checks that the '</include>' checker doesn't flag |line| as an error."""
+    self.assertEqual('', self.checker.IncludeCheck(1, line),
+        'Should not be flagged as style error: ' + line)
+
+  def testIncludeFails(self):
+    lines = [
+        "</include>   ",
+        "    </include>",
+        "    </include>   ",
+        '  <include src="blah.js" />   ',
+        '<include src="blee.js"/>',
+    ]
+    for line in lines:
+      self.ShouldFailIncludeCheck(line)
+
+  def testIncludePasses(self):
+    lines = [
+        '<include src="assert.js">',
+        "<include src='../../assert.js'>",
+        "<i>include src='blah'</i>",
+        "</i>nclude",
+        "</i>include",
+    ]
+    for line in lines:
+      self.ShouldPassIncludeCheck(line)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/web_dev_style/test_util.py b/tools/web_dev_style/test_util.py
new file mode 100644
index 0000000..503db37
--- /dev/null
+++ b/tools/web_dev_style/test_util.py
@@ -0,0 +1,15 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def GetHighlight(line, error):
+  """Returns the substring of |line| that is highlighted in |error|."""
+  error_lines = error.split('\n')
+  # TODO(dschuyler): Splitting the error on \n will prevent index(line)
+  # from finding the line. As a workaround, return the whole, unfiltered
+  # line.
+  if line not in error_lines:
+    return line
+  highlight = error_lines[error_lines.index(line) + 1]
+  return ''.join(ch1 for (ch1, ch2) in zip(line, highlight) if ch2 == '^')
diff --git a/tools/win/DebugVisualizers/BUILD.gn b/tools/win/DebugVisualizers/BUILD.gn
new file mode 100644
index 0000000..6ce6395c
--- /dev/null
+++ b/tools/win/DebugVisualizers/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# The .natvis files define "native visualizers" for the Visual Studio debugger
+# that allow one to define how custom types appear.
+#
+# One can use them by adding them to a project in visual studio, and they can
+# be embedded in a project's PDB file using the undocumented linker flag
+# /NATVIS. These configs would generally be added to all_dependent_configs
+# on a target so all targets that link to them will reference the visualizers
+# from their PDB files.
+#
+# See https://msdn.microsoft.com/en-us/library/jj620914.aspx for how they work.
+#
+# Since these only add ldflags, the targets themselves are not rebuilt when the
+# natvis files are updated. To debug, erase the .pdb file and build to re-link.
+
+assert(is_win)
+
+config("chrome") {
+  ldflags = [ "/NATVIS:" + rebase_path("chrome.natvis", root_build_dir) ]
+}
+
+config("skia") {
+  ldflags = [ "/NATVIS:" + rebase_path("skia.natvis", root_build_dir) ]
+}
+
+config("webkit") {
+  ldflags = [ "/NATVIS:" + rebase_path("webkit.natvis", root_build_dir) ]
+}
diff --git a/tools/win/DebugVisualizers/chrome.natvis b/tools/win/DebugVisualizers/chrome.natvis
index cc3155c7..57a7b62 100644
--- a/tools/win/DebugVisualizers/chrome.natvis
+++ b/tools/win/DebugVisualizers/chrome.natvis
@@ -4,65 +4,14 @@
   <Type Name="gfx::Point">
     <AlternativeType Name="gfx::PointF"/>
     <DisplayString>({x_}, {y_})</DisplayString>
-    <Expand>
-      <Item Name="X">x_</Item>
-      <Item Name="Y">y_</Item>
-    </Expand>
   </Type>
   <Type Name="gfx::Size">
     <AlternativeType Name="gfx::SizeF"/>
     <DisplayString>({width_}, {height_})</DisplayString>
-    <Expand>
-      <Item Name="Width">width_</Item>
-      <Item Name="Height">height_</Item>
-    </Expand>
   </Type>
   <Type Name="gfx::Rect">
     <AlternativeType Name="gfx::RectF"/>
     <DisplayString>({origin_.x_}, {origin_.y_}) x ({size_.width_}, {size_.height_})</DisplayString>
-    <Expand>
-      <Item Name="Left">origin_.x_</Item>
-      <Item Name="Top">origin_.y_</Item>
-      <Item Name="Width">size_.width_</Item>
-      <Item Name="Height">size_.height_</Item>
-    </Expand>
-  </Type>
-  <Type Name="aura::Window::Value">
-    <DisplayString>{name,s}: {value}</DisplayString>
-    <Expand/>
-  </Type>
-  <Type Name="aura::Window">
-    <DisplayString>{name_,s}</DisplayString>
-    <Expand>
-      <Item Name="Name">name_</Item>
-      <Item Name="Id">id_</Item>
-      <Item Name="Parent">parent_</Item>
-      <Item Name="Children">children_</Item>
-      <Item Name="Bounds">bounds_</Item>
-      <Item Name="Type">type_</Item>
-      <Item Name="Visible">visible_</Item>
-      <Item Name="Transparent">transparent_</Item>
-      <!--<Synthetic Name="Property Map">
-        <DisplayString>Size = {prop_map_._Mysize}</DisplayString>
-        <Expand>
-          <TreeItems>
-            <Size>prop_map_._Mysize</Size>
-            <HeadPointer>prop_map_._Myhead-&gt;_Parent</HeadPointer>
-            <LeftPointer>_Left</LeftPointer>
-            <RightPointer>_Right</RightPointer>
-            <ValueNode Condition="_Isnil == 0">_Myval.second</ValueNode>
-          </TreeItems>
-        </Expand>
-      </Synthetic>-->
-      <Item Name="Layer">layer_</Item>
-    </Expand>
-  </Type>
-  <Type Name="scoped_ptr&lt;*,*&gt;">
-    <DisplayString Condition="impl_.data_.ptr == 0">null</DisplayString>
-    <DisplayString>{impl_.data_.ptr}</DisplayString>
-    <Expand>
-      <ExpandedItem>impl_.data_.ptr</ExpandedItem>
-    </Expand>
   </Type>
   <Type Name="scoped_refptr&lt;*&gt;">
     <DisplayString Condition="ptr_ == 0">null</DisplayString>
@@ -182,89 +131,48 @@
   </Type>
   <Type Name="GURL">
     <DisplayString>{spec_}</DisplayString>
+  </Type>
+  <Type Name="base::ManualConstructor&lt;*&gt;">
+    <!-- $T1 expands to the first "*" in the name which is the template
+         type. Use that to cast to the correct value. -->
+    <DisplayString>{*($T1*)space_.data_}</DisplayString>
     <Expand>
-      <Item Name="Spec">spec_</Item>
-      <Item Name="IsValid">is_valid_</Item>
-      <Synthetic Name="Scheme">
-        <DisplayString
-            Condition="parsed_.scheme.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.scheme.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Username">
-        <DisplayString
-            Condition="parsed_.username.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.username.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Password">
-        <DisplayString
-            Condition="parsed_.password.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.password.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Host">
-        <DisplayString
-            Condition="parsed_.host.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.host.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Port">
-        <DisplayString
-            Condition="parsed_.port.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.port.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Path">
-        <DisplayString
-            Condition="parsed_.path.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.path.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Query">
-        <DisplayString
-            Condition="parsed_.query.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.query.begin][</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Ref">
-        <DisplayString Condition="parsed_.ref.len==-1">undefined</DisplayString>
-        <DisplayString>spec_._Myres[parsed_.ref.begin][</DisplayString>
-      </Synthetic>
+      <ExpandedItem>*($T1*)space_.data_</ExpandedItem>
+    </Expand>
+  </Type>
+  <Type Name="base::internal::flat_tree&lt;*&gt;">
+    <AlternativeType Name="base::flat_set&lt;*&gt;"/>
+    <DisplayString>{impl_.body_}</DisplayString>
+    <Expand>
+      <ExpandedItem>impl_.body_</ExpandedItem>
+    </Expand>
+  </Type>
+  <Type Name="base::flat_map&lt;*&gt;">
+    <DisplayString>{impl_.body_}</DisplayString>
+    <Expand>
+      <ExpandedItem>impl_.body_</ExpandedItem>
     </Expand>
   </Type>
   <Type Name="base::Value">
-    <DisplayString>{type_}</DisplayString>
+    <DisplayString Condition="type_ == NONE">NONE</DisplayString>
+    <DisplayString Condition="type_ == BOOLEAN">BOOLEAN {bool_value_}</DisplayString>
+    <DisplayString Condition="type_ == INTEGER">INTEGER {int_value_}</DisplayString>
+    <DisplayString Condition="type_ == DOUBLE">DOUBLE {double_value_}</DisplayString>
+    <DisplayString Condition="type_ == STRING">STRING {string_value_}</DisplayString>
+    <DisplayString Condition="type_ == BINARY">BINARY {binary_value_}</DisplayString>
+    <DisplayString Condition="type_ == DICTIONARY">DICTIONARY {dict_}</DisplayString>
+    <DisplayString Condition="type_ == LIST">LIST {list_}</DisplayString>
     <Expand>
-      <Item Name="Type">type_</Item>
+      <Item Name="[type]">type_</Item>
+      <Item Condition="type_ == BOOLEAN" Name="[boolean]">bool_value_</Item>
+      <Item Condition="type_ == INTEGER" Name="[integer]">int_value_</Item>
+      <Item Condition="type_ == DOUBLE" Name="[double]">double_value_</Item>
+      <Item Condition="type_ == STRING" Name="[string]">string_value_</Item>
+      <Item Condition="type_ == BINARY" Name="[binary]">binary_value_</Item>
+      <!-- Put the members for dictionary and list directly inline without
+           requiring a separate expansion to view. -->
+      <ExpandedItem Condition="type_ == DICTIONARY">dict_</ExpandedItem>
+      <ExpandedItem Condition="type_ == LIST">list_</ExpandedItem>
     </Expand>
   </Type>
-  <Type Name="base::Value">
-    <DisplayString>Fundamental</DisplayString>
-    <Expand>
-      <ExpandedItem>(base::Value*)this,nd</ExpandedItem>
-      <Item Name="Int">integer_value_</Item>
-      <Item Name="Bool">boolean_value_</Item>
-      <Item Name="Double">double_value_</Item>
-    </Expand>
-  </Type>
-  <Type Name="base::Value">
-    <DisplayString>String ({value_})</DisplayString>
-    <Expand>
-      <ExpandedItem>(base::Value*)this,nd</ExpandedItem>
-      <Item Name="Value">value_</Item>
-    </Expand>
-  </Type>
-  <Type Name="base::BinaryValue">
-    <DisplayString>Binary ({size_} byte(s))</DisplayString>
-    <Expand>
-      <ExpandedItem>(base::Value*)this,nd</ExpandedItem>
-      <Item Name="Data">buffer_</Item>
-    </Expand>
-  </Type>
-  <Type Name="base::DictionaryValue">
-    <DisplayString>Dictionary ({dictionary_._Mysize} entries)</DisplayString>
-    <Expand>
-      <ExpandedItem>dictionary_</ExpandedItem>
-    </Expand>
-  </Type>
-  <Type Name="base::ListValue">
-    <DisplayString>List ({list_._Mysize} entries)</DisplayString>
-    <Expand>
-      <ExpandedItem>list_</ExpandedItem>
-    </Expand>
-  </Type>
-</AutoVisualizer>
\ No newline at end of file
+</AutoVisualizer>
diff --git a/tools/win/DebugVisualizers/skia.natvis b/tools/win/DebugVisualizers/skia.natvis
index 40502fd..a69b22d 100644
--- a/tools/win/DebugVisualizers/skia.natvis
+++ b/tools/win/DebugVisualizers/skia.natvis
@@ -4,35 +4,15 @@
   <Type Name="SkPoint">
     <AlternativeType Name="SkIPoint"/>
     <DisplayString>({fX}, {fY})</DisplayString>
-    <Expand>
-      <Item Name="X">fX</Item>
-      <Item Name="Y">fY</Item>
-    </Expand>
   </Type>
   <Type Name="SkSize">
     <DisplayString>({fWidth}, {fHeight})</DisplayString>
-    <Expand>
-      <Item Name="Width">fWidth</Item>
-      <Item Name="Height">fHeight</Item>
-    </Expand>
   </Type>
   <Type Name="SkRect">
     <AlternativeType Name="SkIRect"/>
-    <DisplayString>({fLeft}, {fTop}) x ({fRight - fLeft}, {fBottom - fTop})</DisplayString>
-    <Expand>
-      <Item Name="Left">fLeft</Item>
-      <Item Name="Top">fTop</Item>
-      <Item Name="Right">fRight</Item>
-      <Item Name="Bottom">fBottom</Item>
-      <Synthetic Name="Width">
-        <DisplayString>{fRight - fLeft}</DisplayString>
-      </Synthetic>
-      <Synthetic Name="Height">
-        <DisplayString>{fBottom - fTop}</DisplayString>
-      </Synthetic>
-    </Expand>
+    <DisplayString>({fLeft}, {fTop}), ({fRight}, {fBottom})</DisplayString>
   </Type>
   <Type Name="LogFontTypeface">
     <DisplayString>{fLogFont.lfFaceName,su}</DisplayString>
   </Type>
-</AutoVisualizer>
\ No newline at end of file
+</AutoVisualizer>
diff --git a/tools/xdisplaycheck/BUILD.gn b/tools/xdisplaycheck/BUILD.gn
index 779e1636..064305aa 100644
--- a/tools/xdisplaycheck/BUILD.gn
+++ b/tools/xdisplaycheck/BUILD.gn
@@ -10,6 +10,6 @@
   configs += [ "//build/config/linux:x11" ]
 
   deps = [
-    "//build/config/sanitizers:deps",
+    "//build/config:exe_and_shlib_deps",
   ]
 }