|
|
|
@ -18,18 +18,71 @@ |
|
|
|
|
|
|
|
|
|
#include "gtest/gtest.h" |
|
|
|
|
|
|
|
|
|
#include <grpc/grpc.h> |
|
|
|
|
#include <grpc/support/time.h> |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/experiments/experiments.h" |
|
|
|
|
#include "src/core/lib/gpr/useful.h" |
|
|
|
|
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
|
|
|
|
#include "src/core/lib/gprpp/time.h" |
|
|
|
|
#include "src/core/lib/iomgr/exec_ctx.h" |
|
|
|
|
#include "src/core/lib/resource_quota/resource_quota.h" |
|
|
|
|
#include "src/core/lib/transport/bdp_estimator.h" |
|
|
|
|
|
|
|
|
|
extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type); |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
namespace chttp2 { |
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
constexpr uint64_t kMaxAdvanceTimeMillis = 24ull * 365 * 3600 * 1000; |
|
|
|
|
|
|
|
|
|
auto* g_memory_owner = new MemoryOwner( |
|
|
|
|
ResourceQuota::Default()->memory_quota()->CreateMemoryOwner("test")); |
|
|
|
|
|
|
|
|
|
gpr_timespec g_now; |
|
|
|
|
gpr_timespec now_impl(gpr_clock_type clock_type) { |
|
|
|
|
GPR_ASSERT(clock_type != GPR_TIMESPAN); |
|
|
|
|
gpr_timespec ts = g_now; |
|
|
|
|
ts.clock_type = clock_type; |
|
|
|
|
return ts; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void InitGlobals() { |
|
|
|
|
g_now = {1, 0, GPR_CLOCK_MONOTONIC}; |
|
|
|
|
TestOnlySetProcessEpoch(g_now); |
|
|
|
|
gpr_now_impl = now_impl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AdvanceClockMillis(uint64_t millis) { |
|
|
|
|
ExecCtx exec_ctx; |
|
|
|
|
g_now = gpr_time_add(g_now, gpr_time_from_millis(Clamp(millis, uint64_t(1), |
|
|
|
|
kMaxAdvanceTimeMillis), |
|
|
|
|
GPR_TIMESPAN)); |
|
|
|
|
exec_ctx.InvalidateNow(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class TransportTargetWindowEstimatesMocker |
|
|
|
|
: public chttp2::TestOnlyTransportTargetWindowEstimatesMocker { |
|
|
|
|
public: |
|
|
|
|
explicit TransportTargetWindowEstimatesMocker() {} |
|
|
|
|
|
|
|
|
|
double ComputeNextTargetInitialWindowSizeFromPeriodicUpdate( |
|
|
|
|
double current_target) override { |
|
|
|
|
const double kSmallWindow = 16384; |
|
|
|
|
const double kBigWindow = 1024 * 1024; |
|
|
|
|
// Bounce back and forth between small and big initial windows.
|
|
|
|
|
if (current_target > kSmallWindow) { |
|
|
|
|
return kSmallWindow; |
|
|
|
|
} else { |
|
|
|
|
return kBigWindow; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
TEST(FlowControl, NoOp) { |
|
|
|
|
ExecCtx exec_ctx; |
|
|
|
|
TransportFlowControl tfc("test", true, g_memory_owner); |
|
|
|
@ -38,6 +91,7 @@ TEST(FlowControl, NoOp) { |
|
|
|
|
EXPECT_EQ(tfc.acked_init_window(), 65535); |
|
|
|
|
EXPECT_EQ(tfc.remote_window(), 65535); |
|
|
|
|
EXPECT_EQ(tfc.target_frame_size(), 16384); |
|
|
|
|
EXPECT_EQ(tfc.target_preferred_rx_crypto_frame_size(), INT_MAX); |
|
|
|
|
EXPECT_EQ(sfc.remote_window_delta(), 0); |
|
|
|
|
EXPECT_EQ(sfc.min_progress_size(), 0); |
|
|
|
|
EXPECT_EQ(sfc.announced_window_delta(), 0); |
|
|
|
@ -47,12 +101,16 @@ TEST(FlowControl, SendData) { |
|
|
|
|
ExecCtx exec_ctx; |
|
|
|
|
TransportFlowControl tfc("test", true, g_memory_owner); |
|
|
|
|
StreamFlowControl sfc(&tfc); |
|
|
|
|
int64_t prev_preferred_rx_frame_size = |
|
|
|
|
tfc.target_preferred_rx_crypto_frame_size(); |
|
|
|
|
{ |
|
|
|
|
StreamFlowControl::OutgoingUpdateContext sfc_upd(&sfc); |
|
|
|
|
sfc_upd.SentData(1024); |
|
|
|
|
} |
|
|
|
|
EXPECT_EQ(sfc.remote_window_delta(), -1024); |
|
|
|
|
EXPECT_EQ(tfc.remote_window(), 65535 - 1024); |
|
|
|
|
EXPECT_EQ(tfc.target_preferred_rx_crypto_frame_size(), |
|
|
|
|
prev_preferred_rx_frame_size); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST(FlowControl, InitialTransportUpdate) { |
|
|
|
@ -70,15 +128,52 @@ TEST(FlowControl, InitialStreamUpdate) { |
|
|
|
|
FlowControlAction()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST(FlowControl, PeriodicUpdate) { |
|
|
|
|
ExecCtx exec_ctx; |
|
|
|
|
TransportFlowControl tfc("test", true, g_memory_owner); |
|
|
|
|
constexpr int kNumPeriodicUpdates = 100; |
|
|
|
|
Timestamp next_ping = Timestamp::Now() + Duration::Milliseconds(1000); |
|
|
|
|
uint32_t prev_max_frame_size = tfc.target_frame_size(); |
|
|
|
|
for (int i = 0; i < kNumPeriodicUpdates; i++) { |
|
|
|
|
BdpEstimator* bdp = tfc.bdp_estimator(); |
|
|
|
|
bdp->AddIncomingBytes(1024 + (i * 100)); |
|
|
|
|
// Advance clock till the timestamp of the next ping.
|
|
|
|
|
AdvanceClockMillis((next_ping - Timestamp::Now()).millis()); |
|
|
|
|
bdp->SchedulePing(); |
|
|
|
|
bdp->StartPing(); |
|
|
|
|
AdvanceClockMillis(10); |
|
|
|
|
next_ping = bdp->CompletePing(); |
|
|
|
|
FlowControlAction action = tfc.PeriodicUpdate(); |
|
|
|
|
if (IsTcpFrameSizeTuningEnabled()) { |
|
|
|
|
if (action.send_max_frame_size_update() != |
|
|
|
|
FlowControlAction::Urgency::NO_ACTION_NEEDED) { |
|
|
|
|
prev_max_frame_size = action.max_frame_size(); |
|
|
|
|
} |
|
|
|
|
EXPECT_EQ(action.preferred_rx_crypto_frame_size(), |
|
|
|
|
Clamp(2 * prev_max_frame_size, 16384u, 0x7fffffffu)); |
|
|
|
|
EXPECT_TRUE(action.preferred_rx_crypto_frame_size_update() != |
|
|
|
|
FlowControlAction::Urgency::NO_ACTION_NEEDED); |
|
|
|
|
} else { |
|
|
|
|
EXPECT_EQ(action.preferred_rx_crypto_frame_size(), 0); |
|
|
|
|
EXPECT_TRUE(action.preferred_rx_crypto_frame_size_update() == |
|
|
|
|
FlowControlAction::Urgency::NO_ACTION_NEEDED); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST(FlowControl, RecvData) { |
|
|
|
|
ExecCtx exec_ctx; |
|
|
|
|
TransportFlowControl tfc("test", true, g_memory_owner); |
|
|
|
|
StreamFlowControl sfc(&tfc); |
|
|
|
|
StreamFlowControl::IncomingUpdateContext sfc_upd(&sfc); |
|
|
|
|
int64_t prev_preferred_rx_frame_size = |
|
|
|
|
tfc.target_preferred_rx_crypto_frame_size(); |
|
|
|
|
EXPECT_EQ(absl::OkStatus(), sfc_upd.RecvData(1024)); |
|
|
|
|
sfc_upd.MakeAction(); |
|
|
|
|
EXPECT_EQ(tfc.announced_window(), 65535 - 1024); |
|
|
|
|
EXPECT_EQ(sfc.announced_window_delta(), -1024); |
|
|
|
|
EXPECT_EQ(tfc.target_preferred_rx_crypto_frame_size(), |
|
|
|
|
prev_preferred_rx_frame_size); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST(FlowControl, TrackMinProgressSize) { |
|
|
|
@ -170,5 +265,8 @@ TEST(FlowControl, GradualReadsUpdate) { |
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
|
|
::testing::InitGoogleTest(&argc, argv); |
|
|
|
|
grpc_core::chttp2::g_test_only_transport_target_window_estimates_mocker = |
|
|
|
|
new grpc_core::chttp2::TransportTargetWindowEstimatesMocker(); |
|
|
|
|
grpc_core::chttp2::InitGlobals(); |
|
|
|
|
return RUN_ALL_TESTS(); |
|
|
|
|
} |
|
|
|
|