--- /dev/null
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/transport/bdp_estimator.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "src/core/lib/gpr/useful.h"
+
+grpc_core::TraceFlag grpc_bdp_estimator_trace(false, "bdp_estimator");
+
+namespace grpc_core {
+
+BdpEstimator::BdpEstimator(const char* name)
+ : ping_state_(PingState::UNSCHEDULED),
+ accumulator_(0),
+ estimate_(65536),
+ ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)),
+ inter_ping_delay_(100.0), // start at 100ms
+ stable_estimate_count_(0),
+ bw_est_(0),
+ name_(name) {}
+
+grpc_millis BdpEstimator::CompletePing() {
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_);
+ double dt = static_cast<double>(dt_ts.tv_sec) +
+ 1e-9 * static_cast<double>(dt_ts.tv_nsec);
+ double bw = dt > 0 ? (static_cast<double>(accumulator_) / dt) : 0;
+ int start_inter_ping_delay = inter_ping_delay_;
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) {
+ gpr_log(GPR_INFO,
+ "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64
+ " dt=%lf bw=%lfMbs bw_est=%lfMbs",
+ name_, accumulator_, estimate_, dt, bw / 125000.0,
+ bw_est_ / 125000.0);
+ }
+ GPR_ASSERT(ping_state_ == PingState::STARTED);
+ if (accumulator_ > 2 * estimate_ / 3 && bw > bw_est_) {
+ estimate_ = GPR_MAX(accumulator_, estimate_ * 2);
+ bw_est_ = bw;
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) {
+ gpr_log(GPR_INFO, "bdp[%s]: estimate increased to %" PRId64, name_,
+ estimate_);
+ }
+ inter_ping_delay_ /= 2; // if the ping estimate changes,
+ // exponentially get faster at probing
+ } else if (inter_ping_delay_ < 10000) {
+ stable_estimate_count_++;
+ if (stable_estimate_count_ >= 2) {
+ inter_ping_delay_ +=
+ 100 + static_cast<int>(rand() * 100.0 /
+ RAND_MAX); // if the ping estimate is steady,
+ // slowly ramp down the probe time
+ }
+ }
+ if (start_inter_ping_delay != inter_ping_delay_) {
+ stable_estimate_count_ = 0;
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) {
+ gpr_log(GPR_INFO, "bdp[%s]:update_inter_time to %dms", name_,
+ inter_ping_delay_);
+ }
+ }
+ ping_state_ = PingState::UNSCHEDULED;
+ accumulator_ = 0;
+ return grpc_core::ExecCtx::Get()->Now() + inter_ping_delay_;
+}
+
+} // namespace grpc_core