[xDS] Accept cpu_utilization over 100% (#32954)

<!--

If you know who should review your pull request, please assign it to
that
person, otherwise the pull request would get assigned randomly.

If your pull request is for a specific language, please add the
appropriate
lang label.

-->
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e9911f4..14b7e1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -397,18 +397,18 @@
   # Download the archive via HTTP, validate the checksum, and extract to third_party/xds.
   download_archive(
     ${CMAKE_CURRENT_SOURCE_DIR}/third_party/xds
-    https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz
-    fcd0b50c013452fda9c5e28c131c287b655ebb361271a76ad3bffc08b3ecd82e
-    xds-32f1caf87195bf3390061c29f18987e51ca56a88
+    https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz
+    aef36c29bd0ef95509f7f52693dbdafe4a2c2c5d1eb406bf68e6364a0d12e11b
+    xds-4003588d1b747e37e911baa5a9c1c07fde4ca518
   )
 endif()
 if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/xds)
   # Download the archive via HTTP, validate the checksum, and extract to third_party/xds.
   download_archive(
     ${CMAKE_CURRENT_SOURCE_DIR}/third_party/xds
-    https://github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz
-    fcd0b50c013452fda9c5e28c131c287b655ebb361271a76ad3bffc08b3ecd82e
-    xds-32f1caf87195bf3390061c29f18987e51ca56a88
+    https://github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz
+    aef36c29bd0ef95509f7f52693dbdafe4a2c2c5d1eb406bf68e6364a0d12e11b
+    xds-4003588d1b747e37e911baa5a9c1c07fde4ca518
   )
 endif()
 
diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl
index d741292..0ce108f 100644
--- a/bazel/grpc_deps.bzl
+++ b/bazel/grpc_deps.bzl
@@ -500,11 +500,11 @@
     if "com_github_cncf_udpa" not in native.existing_rules():
         http_archive(
             name = "com_github_cncf_udpa",
-            sha256 = "fcd0b50c013452fda9c5e28c131c287b655ebb361271a76ad3bffc08b3ecd82e",
-            strip_prefix = "xds-32f1caf87195bf3390061c29f18987e51ca56a88",
+            sha256 = "aef36c29bd0ef95509f7f52693dbdafe4a2c2c5d1eb406bf68e6364a0d12e11b",
+            strip_prefix = "xds-4003588d1b747e37e911baa5a9c1c07fde4ca518",
             urls = [
-                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz",
-                "https://github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz",
+                "https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz",
+                "https://github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz",
             ],
         )
 
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 0e92985..a69243a 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -13992,10 +13992,10 @@
   - https://storage.googleapis.com/grpc-bazel-mirror/github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz
   - https://github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz
 - destination: third_party/xds
-  hash: fcd0b50c013452fda9c5e28c131c287b655ebb361271a76ad3bffc08b3ecd82e
+  hash: aef36c29bd0ef95509f7f52693dbdafe4a2c2c5d1eb406bf68e6364a0d12e11b
   proto_prefix: third_party/xds/
-  strip_prefix: xds-32f1caf87195bf3390061c29f18987e51ca56a88
+  strip_prefix: xds-4003588d1b747e37e911baa5a9c1c07fde4ca518
   urls:
-  - https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz
-  - https://github.com/cncf/xds/archive/32f1caf87195bf3390061c29f18987e51ca56a88.tar.gz
+  - https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz
+  - https://github.com/cncf/xds/archive/4003588d1b747e37e911baa5a9c1c07fde4ca518.tar.gz
 tests: []
diff --git a/include/grpcpp/ext/call_metric_recorder.h b/include/grpcpp/ext/call_metric_recorder.h
index 140a0b1..276867a 100644
--- a/include/grpcpp/ext/call_metric_recorder.h
+++ b/include/grpcpp/ext/call_metric_recorder.h
@@ -40,7 +40,9 @@
 
   /// Records a call metric measurement for CPU utilization.
   /// Multiple calls to this method will override the stored value.
-  /// Values outside of the valid range [0, 1] are ignored.
+  /// Values may be larger than 1.0 when the usage exceeds the reporter
+  /// dependent notion of soft limits.
+  /// Values outside of the valid range [0, infy] are ignored.
   virtual CallMetricRecorder& RecordCpuUtilizationMetric(double value) = 0;
 
   /// Records a call metric measurement for memory utilization.
diff --git a/include/grpcpp/ext/server_metric_recorder.h b/include/grpcpp/ext/server_metric_recorder.h
index b0521cb..b93b54b 100644
--- a/include/grpcpp/ext/server_metric_recorder.h
+++ b/include/grpcpp/ext/server_metric_recorder.h
@@ -43,9 +43,10 @@
  public:
   // Factory method. Use this to create.
   static std::unique_ptr<ServerMetricRecorder> Create();
-  /// Records the server CPU utilization in the range [0, 1].
-  /// Values outside of the valid range are rejected.
-  /// Overrides the stored value when called again with a valid value.
+  /// Records the server CPU utilization in the range [0, infy).
+  /// Values may be larger than 1.0 when the usage exceeds the reporter
+  /// dependent notion of soft limits. Values outside of the valid range are
+  /// rejected. Overrides the stored value when called again with a valid value.
   void SetCpuUtilization(double value);
   /// Records the server memory utilization in the range [0, 1].
   /// Values outside of the valid range are rejected.
diff --git a/src/cpp/server/backend_metric_recorder.cc b/src/cpp/server/backend_metric_recorder.cc
index 47a9300..91b2529 100644
--- a/src/cpp/server/backend_metric_recorder.cc
+++ b/src/cpp/server/backend_metric_recorder.cc
@@ -34,7 +34,10 @@
 using grpc_core::BackendMetricData;
 
 namespace {
-// All utilization values must be in [0, 1].
+// CPU utilization values must be in [0, infy).
+bool IsCpuUtilizationValid(double cpu) { return cpu >= 0.0; }
+
+// Other utilization values must be in [0, 1].
 bool IsUtilizationValid(double utilization) {
   return utilization >= 0.0 && utilization <= 1.0;
 }
@@ -65,7 +68,7 @@
 }
 
 void ServerMetricRecorder::SetCpuUtilization(double value) {
-  if (!IsUtilizationValid(value)) {
+  if (!IsCpuUtilizationValid(value)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
       gpr_log(GPR_INFO, "[%p] CPU utilization rejected: %f", this, value);
     }
@@ -220,7 +223,7 @@
 
 experimental::CallMetricRecorder&
 BackendMetricState::RecordCpuUtilizationMetric(double value) {
-  if (!IsUtilizationValid(value)) {
+  if (!IsCpuUtilizationValid(value)) {
     if (GRPC_TRACE_FLAG_ENABLED(grpc_backend_metric_trace)) {
       gpr_log(GPR_INFO, "[%p] CPU utilization value rejected: %f", this, value);
     }
@@ -330,7 +333,7 @@
   }
   // Only overwrite if the value is set i.e. in the valid range.
   const double cpu = cpu_utilization_.load(std::memory_order_relaxed);
-  if (IsUtilizationValid(cpu)) {
+  if (IsCpuUtilizationValid(cpu)) {
     data.cpu_utilization = cpu;
   }
   const double mem = mem_utilization_.load(std::memory_order_relaxed);
diff --git a/src/proto/grpc/testing/xds/v3/orca_load_report.proto b/src/proto/grpc/testing/xds/v3/orca_load_report.proto
index 86422ac..0176a6d 100644
--- a/src/proto/grpc/testing/xds/v3/orca_load_report.proto
+++ b/src/proto/grpc/testing/xds/v3/orca_load_report.proto
@@ -23,7 +23,9 @@
 
 message OrcaLoadReport {
   // CPU utilization expressed as a fraction of available CPU resources. This
-  // should be derived from the latest sample or measurement.
+  // should be derived from the latest sample or measurement. The value may be
+  // larger than 1.0 when the usage exceeds the reporter dependent notion of
+  // soft limits.
   double cpu_utilization = 1;
 
   // Memory utilization expressed as a fraction of available memory
diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc
index a783c45..e4ae40a 100644
--- a/test/cpp/end2end/client_lb_end2end_test.cc
+++ b/test/cpp/end2end/client_lb_end2end_test.cc
@@ -84,6 +84,7 @@
 namespace testing {
 namespace {
 
+using xds::data::orca::v3::OrcaLoadReport;
 constexpr char kRequestMessage[] = "Live long and prosper.";
 
 // A noop health check service that just terminates the call and returns OK
@@ -380,8 +381,7 @@
   void CheckRpcSendOk(
       const grpc_core::DebugLocation& location,
       const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
-      bool wait_for_ready = false,
-      xds::data::orca::v3::OrcaLoadReport* load_report = nullptr,
+      bool wait_for_ready = false, const OrcaLoadReport* load_report = nullptr,
       int timeout_ms = 2000) {
     EchoResponse response;
     EchoRequest request;
@@ -2345,30 +2345,94 @@
       << ArgsSeenListString(pick_args_seen_list);
 }
 
+class OrcaLoadReportBuilder {
+ public:
+  OrcaLoadReportBuilder() = default;
+  explicit OrcaLoadReportBuilder(const OrcaLoadReport& report)
+      : report_(report) {}
+  OrcaLoadReportBuilder& SetCpuUtilization(double v) {
+    report_.set_cpu_utilization(v);
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetMemUtilization(double v) {
+    report_.set_mem_utilization(v);
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetQps(double v) {
+    report_.set_rps_fractional(v);
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetEps(double v) {
+    report_.set_eps(v);
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetRequestCost(absl::string_view n, double v) {
+    (*report_.mutable_request_cost())[n] = v;
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetUtilization(absl::string_view n, double v) {
+    (*report_.mutable_utilization())[n] = v;
+    return *this;
+  }
+  OrcaLoadReportBuilder& SetNamedMetrics(absl::string_view n, double v) {
+    (*report_.mutable_named_metrics())[n] = v;
+    return *this;
+  }
+  OrcaLoadReport Build() { return std::move(report_); }
+
+ private:
+  OrcaLoadReport report_;
+};
+
 //
 // tests that LB policies can get the call's trailing metadata
 //
 
-xds::data::orca::v3::OrcaLoadReport BackendMetricDataToOrcaLoadReport(
+OrcaLoadReport BackendMetricDataToOrcaLoadReport(
     const grpc_core::BackendMetricData& backend_metric_data) {
-  xds::data::orca::v3::OrcaLoadReport load_report;
-  load_report.set_cpu_utilization(backend_metric_data.cpu_utilization);
-  load_report.set_mem_utilization(backend_metric_data.mem_utilization);
-  load_report.set_rps_fractional(backend_metric_data.qps);
-  load_report.set_eps(backend_metric_data.eps);
+  auto builder = OrcaLoadReportBuilder()
+                     .SetCpuUtilization(backend_metric_data.cpu_utilization)
+                     .SetMemUtilization(backend_metric_data.mem_utilization)
+                     .SetQps(backend_metric_data.qps)
+                     .SetEps(backend_metric_data.eps);
   for (const auto& p : backend_metric_data.request_cost) {
-    std::string name(p.first);
-    (*load_report.mutable_request_cost())[name] = p.second;
+    builder.SetRequestCost(std::string(p.first), p.second);
   }
   for (const auto& p : backend_metric_data.utilization) {
-    std::string name(p.first);
-    (*load_report.mutable_utilization())[name] = p.second;
+    builder.SetUtilization(std::string(p.first), p.second);
   }
   for (const auto& p : backend_metric_data.named_metrics) {
-    std::string name(p.first);
-    (*load_report.mutable_named_metrics())[name] = p.second;
+    builder.SetNamedMetrics(std::string(p.first), p.second);
   }
-  return load_report;
+  return builder.Build();
+}
+
+// TODO(roth): Change this to use EqualsProto() once that becomes available in
+// OSS.
+void CheckLoadReportAsExpected(const OrcaLoadReport& actual,
+                               const OrcaLoadReport& expected) {
+  EXPECT_EQ(actual.cpu_utilization(), expected.cpu_utilization());
+  EXPECT_EQ(actual.mem_utilization(), expected.mem_utilization());
+  EXPECT_EQ(actual.rps_fractional(), expected.rps_fractional());
+  EXPECT_EQ(actual.eps(), expected.eps());
+  EXPECT_EQ(actual.request_cost().size(), expected.request_cost().size());
+  for (const auto& p : actual.request_cost()) {
+    auto it = expected.request_cost().find(p.first);
+    ASSERT_NE(it, expected.request_cost().end());
+    EXPECT_EQ(it->second, p.second);
+  }
+  EXPECT_EQ(actual.utilization().size(), expected.utilization().size());
+  for (const auto& p : actual.utilization()) {
+    auto it = expected.utilization().find(p.first);
+    ASSERT_NE(it, expected.utilization().end());
+    EXPECT_EQ(it->second, p.second);
+  }
+  EXPECT_EQ(actual.named_metrics().size(), expected.named_metrics().size());
+  for (const auto& p : actual.named_metrics()) {
+    auto it = expected.named_metrics().find(p.first);
+    ASSERT_NE(it, expected.named_metrics().end());
+    EXPECT_EQ(it->second, p.second);
+  }
 }
 
 class ClientLbInterceptTrailingMetadataTest : public ClientLbEnd2endTest {
@@ -2408,7 +2472,7 @@
     return std::move(trailing_metadata_);
   }
 
-  absl::optional<xds::data::orca::v3::OrcaLoadReport> backend_load_report() {
+  absl::optional<OrcaLoadReport> backend_load_report() {
     grpc_core::MutexLock lock(&mu_);
     return std::move(load_report_);
   }
@@ -2423,6 +2487,28 @@
     return true;
   }
 
+  void RunPerRpcMetricReportingTest(const OrcaLoadReport& reported,
+                                    const OrcaLoadReport& expected) {
+    const int kNumServers = 1;
+    const int kNumRpcs = 10;
+    StartServers(kNumServers);
+    auto response_generator = BuildResolverResponseGenerator();
+    auto channel =
+        BuildChannel("intercept_trailing_metadata_lb", response_generator);
+    auto stub = BuildStub(channel);
+    response_generator.SetNextResolution(GetServersPorts());
+    for (size_t i = 0; i < kNumRpcs; ++i) {
+      CheckRpcSendOk(DEBUG_LOCATION, stub, false, &reported);
+      auto actual = backend_load_report();
+      ASSERT_TRUE(actual.has_value());
+      CheckLoadReportAsExpected(*actual, expected);
+    }
+    // Check LB policy name for the channel.
+    EXPECT_EQ("intercept_trailing_metadata_lb",
+              channel->GetLoadBalancingPolicyName());
+    EXPECT_EQ(kNumRpcs, num_trailers_intercepted());
+  }
+
  private:
   static void ReportTrailerIntercepted(
       const grpc_core::TrailingMetadataArgsSeen& args_seen) {
@@ -2447,7 +2533,7 @@
   grpc_core::CondVar cond_;
   absl::Status last_status_;
   grpc_core::MetadataVector trailing_metadata_;
-  absl::optional<xds::data::orca::v3::OrcaLoadReport> load_report_;
+  absl::optional<OrcaLoadReport> load_report_;
 };
 
 ClientLbInterceptTrailingMetadataTest*
@@ -2583,74 +2669,62 @@
   EXPECT_FALSE(backend_load_report().has_value());
 }
 
-// TODO(roth): Change this to use EqualsProto() once that becomes available in
-// OSS.
-void CheckLoadReportAsExpected(
-    const xds::data::orca::v3::OrcaLoadReport& actual,
-    const xds::data::orca::v3::OrcaLoadReport& expected) {
-  EXPECT_EQ(actual.cpu_utilization(), expected.cpu_utilization());
-  EXPECT_EQ(actual.mem_utilization(), expected.mem_utilization());
-  EXPECT_EQ(actual.rps_fractional(), expected.rps_fractional());
-  EXPECT_EQ(actual.eps(), expected.eps());
-  EXPECT_EQ(actual.request_cost().size(), expected.request_cost().size());
-  for (const auto& p : actual.request_cost()) {
-    auto it = expected.request_cost().find(p.first);
-    ASSERT_NE(it, expected.request_cost().end());
-    EXPECT_EQ(it->second, p.second);
-  }
-  EXPECT_EQ(actual.utilization().size(), expected.utilization().size());
-  for (const auto& p : actual.utilization()) {
-    auto it = expected.utilization().find(p.first);
-    ASSERT_NE(it, expected.utilization().end());
-    EXPECT_EQ(it->second, p.second);
-  }
-  EXPECT_EQ(actual.named_metrics().size(), expected.named_metrics().size());
-  for (const auto& p : actual.named_metrics()) {
-    auto it = expected.named_metrics().find(p.first);
-    ASSERT_NE(it, expected.named_metrics().end());
-    EXPECT_EQ(it->second, p.second);
-  }
+TEST_F(ClientLbInterceptTrailingMetadataTest, Valid) {
+  RunPerRpcMetricReportingTest(OrcaLoadReportBuilder()
+                                   .SetCpuUtilization(0.5)
+                                   .SetMemUtilization(0.75)
+                                   .SetQps(0.25)
+                                   .SetEps(0.1)
+                                   .SetRequestCost("foo", -0.8)
+                                   .SetRequestCost("bar", 1.4)
+                                   .SetUtilization("baz", 1.0)
+                                   .SetUtilization("quux", 0.9)
+                                   .SetNamedMetrics("metric0", 3.0)
+                                   .SetNamedMetrics("metric1", -1.0)
+                                   .Build(),
+                               OrcaLoadReportBuilder()
+                                   .SetCpuUtilization(0.5)
+                                   .SetMemUtilization(0.75)
+                                   .SetQps(0.25)
+                                   .SetEps(0.1)
+                                   .SetRequestCost("foo", -0.8)
+                                   .SetRequestCost("bar", 1.4)
+                                   .SetUtilization("baz", 1.0)
+                                   .SetUtilization("quux", 0.9)
+                                   .SetNamedMetrics("metric0", 3.0)
+                                   .SetNamedMetrics("metric1", -1.0)
+                                   .Build());
 }
 
-TEST_F(ClientLbInterceptTrailingMetadataTest, BackendMetricData) {
-  const int kNumServers = 1;
-  const int kNumRpcs = 10;
-  StartServers(kNumServers);
-  xds::data::orca::v3::OrcaLoadReport load_report;
-  load_report.set_cpu_utilization(0.5);
-  load_report.set_mem_utilization(0.75);
-  load_report.set_rps_fractional(0.25);
-  load_report.set_eps(0.10);
-  auto& request_cost = *load_report.mutable_request_cost();
-  request_cost["foo"] = -0.8;
-  request_cost["bar"] = 1.4;
-  auto& utilization = *load_report.mutable_utilization();
-  utilization["baz"] = 1.0;
-  utilization["quux"] = 0.9;
-  // This will be rejected.
-  utilization["out_of_range_invalid1"] = 1.1;
-  utilization["out_of_range_invalid2"] = -1.1;
-  auto& named_metrics = *load_report.mutable_named_metrics();
-  named_metrics["metric0"] = 3.0;
-  named_metrics["metric1"] = -1.0;
-  auto expected = load_report;
-  expected.mutable_utilization()->erase("out_of_range_invalid1");
-  expected.mutable_utilization()->erase("out_of_range_invalid2");
-  auto response_generator = BuildResolverResponseGenerator();
-  auto channel =
-      BuildChannel("intercept_trailing_metadata_lb", response_generator);
-  auto stub = BuildStub(channel);
-  response_generator.SetNextResolution(GetServersPorts());
-  for (size_t i = 0; i < kNumRpcs; ++i) {
-    CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
-    auto actual = backend_load_report();
-    ASSERT_TRUE(actual.has_value());
-    CheckLoadReportAsExpected(*actual, expected);
-  }
-  // Check LB policy name for the channel.
-  EXPECT_EQ("intercept_trailing_metadata_lb",
-            channel->GetLoadBalancingPolicyName());
-  EXPECT_EQ(kNumRpcs, num_trailers_intercepted());
+TEST_F(ClientLbInterceptTrailingMetadataTest, NegativeValues) {
+  RunPerRpcMetricReportingTest(OrcaLoadReportBuilder()
+                                   .SetCpuUtilization(-0.1)
+                                   .SetMemUtilization(-0.2)
+                                   .SetQps(-3)
+                                   .SetEps(-4)
+                                   .SetRequestCost("foo", -5)
+                                   .SetUtilization("bar", -0.6)
+                                   .SetNamedMetrics("baz", -0.7)
+                                   .Build(),
+                               OrcaLoadReportBuilder()
+                                   .SetRequestCost("foo", -5)
+                                   .SetNamedMetrics("baz", -0.7)
+                                   .Build());
+}
+
+TEST_F(ClientLbInterceptTrailingMetadataTest, AboveOneUtilization) {
+  RunPerRpcMetricReportingTest(OrcaLoadReportBuilder()
+                                   .SetCpuUtilization(1.1)
+                                   .SetMemUtilization(2)
+                                   .SetQps(3)
+                                   .SetEps(4)
+                                   .SetUtilization("foo", 5)
+                                   .Build(),
+                               OrcaLoadReportBuilder()
+                                   .SetCpuUtilization(1.1)
+                                   .SetQps(3)
+                                   .SetEps(4)
+                                   .Build());
 }
 
 TEST_F(ClientLbInterceptTrailingMetadataTest, BackendMetricDataMerge) {
@@ -2663,13 +2737,14 @@
   servers_[0]->server_metric_recorder_->SetEps(0.99);
   servers_[0]->server_metric_recorder_->SetNamedUtilization("foo", 0.99);
   servers_[0]->server_metric_recorder_->SetNamedUtilization("bar", 0.1);
-  xds::data::orca::v3::OrcaLoadReport per_server_load;
-  per_server_load.set_cpu_utilization(0.99);
-  per_server_load.set_mem_utilization(0.99);
-  per_server_load.set_rps_fractional(0.99);
-  per_server_load.set_eps(0.99);
-  (*per_server_load.mutable_utilization())["foo"] = 0.99;
-  (*per_server_load.mutable_utilization())["bar"] = 0.1;
+  OrcaLoadReport per_server_load = OrcaLoadReportBuilder()
+                                       .SetCpuUtilization(0.99)
+                                       .SetMemUtilization(0.99)
+                                       .SetQps(0.99)
+                                       .SetEps(0.99)
+                                       .SetUtilization("foo", 0.99)
+                                       .SetUtilization("bar", 0.1)
+                                       .Build();
   auto response_generator = BuildResolverResponseGenerator();
   auto channel =
       BuildChannel("intercept_trailing_metadata_lb", response_generator);
@@ -2677,10 +2752,10 @@
   response_generator.SetNextResolution(GetServersPorts());
   size_t total_num_rpcs = 0;
   {
-    xds::data::orca::v3::OrcaLoadReport load_report;
-    load_report.set_cpu_utilization(0.5);
-    auto expected = per_server_load;
-    expected.set_cpu_utilization(0.5);
+    OrcaLoadReport load_report =
+        OrcaLoadReportBuilder().SetCpuUtilization(0.5).Build();
+    OrcaLoadReport expected =
+        OrcaLoadReportBuilder(per_server_load).SetCpuUtilization(0.5).Build();
     for (size_t i = 0; i < kNumRpcs; ++i) {
       CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
       auto actual = backend_load_report();
@@ -2690,10 +2765,10 @@
     }
   }
   {
-    xds::data::orca::v3::OrcaLoadReport load_report;
-    load_report.set_mem_utilization(0.5);
-    auto expected = per_server_load;
-    expected.set_mem_utilization(0.5);
+    OrcaLoadReport load_report =
+        OrcaLoadReportBuilder().SetMemUtilization(0.5).Build();
+    OrcaLoadReport expected =
+        OrcaLoadReportBuilder(per_server_load).SetMemUtilization(0.5).Build();
     for (size_t i = 0; i < kNumRpcs; ++i) {
       CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
       auto actual = backend_load_report();
@@ -2703,10 +2778,9 @@
     }
   }
   {
-    xds::data::orca::v3::OrcaLoadReport load_report;
-    load_report.set_rps_fractional(0.5);
-    auto expected = per_server_load;
-    expected.set_rps_fractional(0.5);
+    OrcaLoadReport load_report = OrcaLoadReportBuilder().SetQps(0.5).Build();
+    OrcaLoadReport expected =
+        OrcaLoadReportBuilder(per_server_load).SetQps(0.5).Build();
     for (size_t i = 0; i < kNumRpcs; ++i) {
       CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
       auto actual = backend_load_report();
@@ -2716,10 +2790,9 @@
     }
   }
   {
-    xds::data::orca::v3::OrcaLoadReport load_report;
-    load_report.set_eps(0.5);
-    auto expected = per_server_load;
-    expected.set_eps(0.5);
+    OrcaLoadReport load_report = OrcaLoadReportBuilder().SetEps(0.5).Build();
+    OrcaLoadReport expected =
+        OrcaLoadReportBuilder(per_server_load).SetEps(0.5).Build();
     for (size_t i = 0; i < kNumRpcs; ++i) {
       CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
       auto actual = backend_load_report();
@@ -2729,15 +2802,16 @@
     }
   }
   {
-    xds::data::orca::v3::OrcaLoadReport load_report;
-    auto& utilization = *load_report.mutable_utilization();
-    utilization["foo"] = 0.5;
-    // Out of range, won't override.
-    utilization["bar"] = 1.1;
-    utilization["baz"] = 1.0;
-    auto expected = per_server_load;
-    (*expected.mutable_utilization())["foo"] = 0.5;
-    (*expected.mutable_utilization())["baz"] = 1.0;
+    OrcaLoadReport load_report =
+        OrcaLoadReportBuilder()
+            .SetUtilization("foo", 0.5)
+            .SetUtilization("bar", 1.1)  // Out of range.
+            .SetUtilization("baz", 1.0)
+            .Build();
+    auto expected = OrcaLoadReportBuilder(per_server_load)
+                        .SetUtilization("foo", 0.5)
+                        .SetUtilization("baz", 1.0)
+                        .Build();
     for (size_t i = 0; i < kNumRpcs; ++i) {
       CheckRpcSendOk(DEBUG_LOCATION, stub, false, &load_report);
       auto actual = backend_load_report();
@@ -2848,8 +2922,7 @@
 
 class OobBackendMetricTest : public ClientLbEnd2endTest {
  protected:
-  using BackendMetricReport =
-      std::pair<int /*port*/, xds::data::orca::v3::OrcaLoadReport>;
+  using BackendMetricReport = std::pair<int /*port*/, OrcaLoadReport>;
 
   void SetUp() override {
     ClientLbEnd2endTest::SetUp();
@@ -2943,7 +3016,7 @@
   servers_[0]->server_metric_recorder_->SetEps(0.6);
   servers_[0]->server_metric_recorder_->SetQps(0.8);
   servers_[0]->server_metric_recorder_->SetMemoryUtilization(0.5);
-  servers_[0]->server_metric_recorder_->SetCpuUtilization(0.4);
+  servers_[0]->server_metric_recorder_->SetCpuUtilization(2.4);
   // Wait for client to see new report.
   report_seen = false;
   for (size_t i = 0; i < 5; ++i) {
@@ -2951,7 +3024,7 @@
     if (report.has_value()) {
       EXPECT_EQ(report->first, servers_[0]->port_);
       if (report->second.cpu_utilization() != 0.1) {
-        EXPECT_EQ(report->second.cpu_utilization(), 0.4);
+        EXPECT_EQ(report->second.cpu_utilization(), 2.4);
         EXPECT_EQ(report->second.mem_utilization(), 0.5);
         EXPECT_EQ(report->second.eps(), 0.6);
         EXPECT_EQ(report->second.rps_fractional(), 0.8);
@@ -3121,17 +3194,17 @@
 TEST_F(WeightedRoundRobinTest, CallAndServerMetric) {
   const int kNumServers = 3;
   StartServers(kNumServers);
-  // Report server metrics that should give 1:2:4 WRR picks.
+  // Report server metrics that should give 6:4:3 WRR picks.
   // weights = qps / (cpu_util + (eps/qps)) =
-  //   1/(0.4+0.4) : 1/(0.2+0.2) : 2/(0.3+0.1) = 1:2:4
-  servers_[0]->server_metric_recorder_->SetCpuUtilization(0.4);
-  servers_[0]->server_metric_recorder_->SetEps(40);
+  //   1/(0.2+0.2) : 1/(0.3+0.3) : 2/(1.5+0.1) = 6:4:3
+  servers_[0]->server_metric_recorder_->SetCpuUtilization(0.2);
+  servers_[0]->server_metric_recorder_->SetEps(20);
   servers_[0]->server_metric_recorder_->SetQps(100);
-  servers_[1]->server_metric_recorder_->SetCpuUtilization(0.2);
-  servers_[1]->server_metric_recorder_->SetEps(20);
+  servers_[1]->server_metric_recorder_->SetCpuUtilization(0.3);
+  servers_[1]->server_metric_recorder_->SetEps(30);
   servers_[1]->server_metric_recorder_->SetQps(100);
-  servers_[2]->server_metric_recorder_->SetCpuUtilization(0.3);
-  servers_[2]->server_metric_recorder_->SetEps(5);
+  servers_[2]->server_metric_recorder_->SetCpuUtilization(1.5);
+  servers_[2]->server_metric_recorder_->SetEps(20);
   servers_[2]->server_metric_recorder_->SetQps(200);
   // Create channel.
   auto response_generator = BuildResolverResponseGenerator();
@@ -3140,20 +3213,19 @@
   response_generator.SetNextResolution(GetServersPorts(),
                                        kServiceConfigPerCall);
   // Send requests with per-call reported EPS/QPS set to 0/100.
-  // This should override per-server QPS above and give 1/4:1/2:1/3 = 3:6:4 WRR
-  // picks.
+  // This should give 1/2:1/3:1/15 = 15:10:2 WRR picks.
   EchoRequest request;
   // We cannot override with 0 with proto3, so setting it to almost 0.
   request.mutable_param()->mutable_backend_metrics()->set_eps(
       std::numeric_limits<double>::min());
   request.mutable_param()->mutable_backend_metrics()->set_rps_fractional(100);
   ExpectWeightedRoundRobinPicks(DEBUG_LOCATION, stub,
-                                /*expected_weights=*/{3, 6, 4},
+                                /*expected_weights=*/{15, 10, 2},
                                 /*total_passes=*/3, &request);
   // Now send requests without per-call reported QPS.
-  // This should change WRR picks back to 1:2:4.
+  // This should change WRR picks back to 6:4:3.
   ExpectWeightedRoundRobinPicks(DEBUG_LOCATION, stub,
-                                /*expected_weights=*/{1, 2, 4});
+                                /*expected_weights=*/{6, 4, 3});
   // Check LB policy name for the channel.
   EXPECT_EQ("weighted_round_robin", channel->GetLoadBalancingPolicyName());
 }
diff --git a/test/cpp/end2end/orca_service_end2end_test.cc b/test/cpp/end2end/orca_service_end2end_test.cc
index a1d9ec3..c14be72 100644
--- a/test/cpp/end2end/orca_service_end2end_test.cc
+++ b/test/cpp/end2end/orca_service_end2end_test.cc
@@ -153,10 +153,10 @@
     EXPECT_THAT(response.utilization(), ::testing::UnorderedElementsAre());
   });
   // Update CPU utilization and set memory utilization.
-  server_metric_recorder_->SetCpuUtilization(0.8);
+  server_metric_recorder_->SetCpuUtilization(1.8);
   server_metric_recorder_->SetMemoryUtilization(0.4);
   ReadResponses([](const OrcaLoadReport& response) {
-    EXPECT_EQ(response.cpu_utilization(), 0.8);
+    EXPECT_EQ(response.cpu_utilization(), 1.8);
     EXPECT_EQ(response.mem_utilization(), 0.4);
     EXPECT_THAT(response.utilization(), ::testing::UnorderedElementsAre());
   });
diff --git a/test/cpp/end2end/xds/xds_wrr_end2end_test.cc b/test/cpp/end2end/xds/xds_wrr_end2end_test.cc
index 6af40c3..caddca7 100644
--- a/test/cpp/end2end/xds/xds_wrr_end2end_test.cc
+++ b/test/cpp/end2end/xds/xds_wrr_end2end_test.cc
@@ -51,16 +51,16 @@
   ScopedExperimentalEnvVar env_var2("GRPC_EXPERIMENTAL_XDS_WRR_LB");
   CreateAndStartBackends(3);
   // Expected weights = qps / (cpu_util + (eps/qps)) =
-  //   1/(0.4+0.4) : 1/(0.2+0.2) : 1/(0.1+0.1) = 1:2:4
+  //   1/(0.2+0.2) : 1/(0.3+0.3) : 2/(1.5+0.1) = 6:4:3
   backends_[0]->server_metric_recorder()->SetQps(100);
-  backends_[0]->server_metric_recorder()->SetEps(40);
-  backends_[0]->server_metric_recorder()->SetCpuUtilization(0.4);
+  backends_[0]->server_metric_recorder()->SetEps(20);
+  backends_[0]->server_metric_recorder()->SetCpuUtilization(0.2);
   backends_[1]->server_metric_recorder()->SetQps(100);
-  backends_[1]->server_metric_recorder()->SetEps(20);
-  backends_[1]->server_metric_recorder()->SetCpuUtilization(0.2);
-  backends_[2]->server_metric_recorder()->SetQps(100);
-  backends_[2]->server_metric_recorder()->SetEps(10);
-  backends_[2]->server_metric_recorder()->SetCpuUtilization(0.1);
+  backends_[1]->server_metric_recorder()->SetEps(30);
+  backends_[1]->server_metric_recorder()->SetCpuUtilization(0.3);
+  backends_[2]->server_metric_recorder()->SetQps(200);
+  backends_[2]->server_metric_recorder()->SetEps(20);
+  backends_[2]->server_metric_recorder()->SetCpuUtilization(1.5);
   auto cluster = default_cluster_;
   WrrLocality wrr_locality;
   wrr_locality.mutable_endpoint_picking_policy()
@@ -78,14 +78,14 @@
   balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
   size_t num_picks = 0;
   SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult&) {
-    if (++num_picks == 7) {
+    if (++num_picks == 13) {
       gpr_log(GPR_INFO, "request counts: %" PRIuPTR " %" PRIuPTR " %" PRIuPTR,
               backends_[0]->backend_service()->request_count(),
               backends_[1]->backend_service()->request_count(),
               backends_[2]->backend_service()->request_count());
-      if (backends_[0]->backend_service()->request_count() == 1 &&
-          backends_[1]->backend_service()->request_count() == 2 &&
-          backends_[2]->backend_service()->request_count() == 4) {
+      if (backends_[0]->backend_service()->request_count() == 6 &&
+          backends_[1]->backend_service()->request_count() == 4 &&
+          backends_[2]->backend_service()->request_count() == 3) {
         return false;
       }
       num_picks = 0;
diff --git a/third_party/xds b/third_party/xds
index 32f1caf..4003588 160000
--- a/third_party/xds
+++ b/third_party/xds
@@ -1 +1 @@
-Subproject commit 32f1caf87195bf3390061c29f18987e51ca56a88
+Subproject commit 4003588d1b747e37e911baa5a9c1c07fde4ca518
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 6874a03..f276cf7 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -38,7 +38,7 @@
 third_party/opentelemetry 60fa8754d890b5c55949a8c68dcfd7ab5c2395df
 third_party/protobuf 5ddb1fc609d2416e8575c9e7435c608222c2edb2
 third_party/re2 0c5616df9c0aaa44c9440d87422012423d91c7d1
-third_party/xds 32f1caf87195bf3390061c29f18987e51ca56a88
+third_party/xds 4003588d1b747e37e911baa5a9c1c07fde4ca518
 third_party/zlib 04f42ceca40f73e2978b50e93806c2a18c1281fc
 EOF