mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-08 09:42:06 +03:00
Instrumentation callback foundation w/ app rate limited
Summary: Adds `QuicSocket::InstrumentationObserver`, an observer that can be registered to receive various transport events. The ultimate goal of this class is to provide an interface similar to what we have through TCP tracepoints. This means we need to be able to register multiple callbacks. - Initially, the first event exposed through the callback is app rate limited. In the future, we will expose retransmissions (which are loss + TLP), loss events (confirmed), spurious retransmits, RTT measurements, and raw ACK / send operations to enable throughput and goodput measurements. - Multiple callbacks can be registered, but a `folly::small_vector` is used to minimize memory overhead in the common case of between 0 and 2 callbacks registered. - We currently have a few different callback classes to support instrumentation, including `QuicTransportStatsCallback` and `QLogger`. However, neither of these meet our needs: - We only support installing a single transport stats callback and QLogger callback, and they're both specialized to specific use cases. TransportStats is about understanding in aggregation how often an event (like CWND limited) is occurring, and QLogger is about logging a specific event, instead of notifying a callback about an event and allowing it to decide how to proceed. - Ideally, we can find a way to create a callback class that handles all three cases; we can start strategizing around that as we extend `InstrumentationObserver` and identify overlap. Differential Revision: D21923745 fbshipit-source-id: 9fb4337d55ba3e96a89dccf035f2f6978761583e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e43eb2e8b4
commit
ad8ca14760
@@ -2968,5 +2968,84 @@ TEST_F(QuicTransportImplTest, LifecycleObserverMultipleAttachDestroyTransport) {
|
||||
Mock::VerifyAndClearExpectations(cb2.get());
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportImplTest, InstrumentationObserverAttachRemove) {
|
||||
auto cb = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(), UnorderedElementsAre(cb.get()));
|
||||
EXPECT_CALL(*cb, observerDetach(transport.get()));
|
||||
EXPECT_TRUE(transport->removeInstrumentationObserver(cb.get()));
|
||||
Mock::VerifyAndClearExpectations(cb.get());
|
||||
EXPECT_THAT(transport->getInstrumentationObservers(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportImplTest, InstrumentationObserverRemoveMissing) {
|
||||
auto cb = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
EXPECT_FALSE(transport->removeInstrumentationObserver(cb.get()));
|
||||
EXPECT_THAT(transport->getInstrumentationObservers(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportImplTest, InstrumentationObserverAttachDestroyTransport) {
|
||||
auto cb = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(), UnorderedElementsAre(cb.get()));
|
||||
EXPECT_CALL(*cb, observerDetach(transport.get()));
|
||||
transport = nullptr;
|
||||
Mock::VerifyAndClearExpectations(cb.get());
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportImplTest, InstrumentationObserverMultipleAttachRemove) {
|
||||
auto cb1 = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb1.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(),
|
||||
UnorderedElementsAre(cb1.get()));
|
||||
|
||||
auto cb2 = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb2.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(),
|
||||
UnorderedElementsAre(cb1.get(), cb2.get()));
|
||||
|
||||
EXPECT_CALL(*cb2, observerDetach(transport.get()));
|
||||
EXPECT_TRUE(transport->removeInstrumentationObserver(cb2.get()));
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(),
|
||||
UnorderedElementsAre(cb1.get()));
|
||||
Mock::VerifyAndClearExpectations(cb1.get());
|
||||
Mock::VerifyAndClearExpectations(cb2.get());
|
||||
|
||||
EXPECT_CALL(*cb1, observerDetach(transport.get()));
|
||||
EXPECT_TRUE(transport->removeInstrumentationObserver(cb1.get()));
|
||||
EXPECT_THAT(transport->getInstrumentationObservers(), IsEmpty());
|
||||
Mock::VerifyAndClearExpectations(cb1.get());
|
||||
Mock::VerifyAndClearExpectations(cb2.get());
|
||||
|
||||
transport = nullptr;
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
QuicTransportImplTest,
|
||||
InstrumentationObserverMultipleAttachDestroyTransport) {
|
||||
auto cb1 = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb1.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(),
|
||||
UnorderedElementsAre(cb1.get()));
|
||||
|
||||
auto cb2 = std::make_unique<StrictMock<MockInstrumentationObserver>>();
|
||||
transport->addInstrumentationObserver(cb2.get());
|
||||
EXPECT_THAT(
|
||||
transport->getInstrumentationObservers(),
|
||||
UnorderedElementsAre(cb1.get(), cb2.get()));
|
||||
|
||||
EXPECT_CALL(*cb1, observerDetach(transport.get()));
|
||||
EXPECT_CALL(*cb2, observerDetach(transport.get()));
|
||||
transport = nullptr;
|
||||
Mock::VerifyAndClearExpectations(cb1.get());
|
||||
Mock::VerifyAndClearExpectations(cb2.get());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace quic
|
||||
|
Reference in New Issue
Block a user