Skip to content
This repository has been archived by the owner on Aug 11, 2020. It is now read-only.

Commit

Permalink
quic: support memory tracking
Browse files Browse the repository at this point in the history
Fixes: #59
  • Loading branch information
addaleax committed Oct 3, 2019
1 parent fe175ee commit b12befc
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 8 deletions.
28 changes: 28 additions & 0 deletions src/node_quic_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,24 @@ bool QuicSession::UpdateKey() {
&crypto_ctx_);
}

void QuicSession::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("alpn", alpn_);
tracker->TrackField("idle", idle_);
tracker->TrackField("retransmit", retransmit_);
tracker->TrackField("rx_secret", rx_secret_);
tracker->TrackField("tx_secret", tx_secret_);
tracker->TrackField("sendbuf", sendbuf_);
tracker->TrackField("handshake", handshake_);
tracker->TrackField("txbuf", txbuf_);
tracker->TrackField("peer_handshake", peer_handshake_);
tracker->TrackField("streams", streams_);
tracker->TrackField("state", state_);
tracker->TrackField("crypto_rx_ack", crypto_rx_ack_);
tracker->TrackField("crypto_handshake_rate", crypto_handshake_rate_);
tracker->TrackField("stats_buffer", stats_buffer_);
tracker->TrackField("recovery_stats_buffer", recovery_stats_buffer_);
tracker->TrackFieldWithSize("current_ngtcp2_memory", current_ngtcp2_memory_);
}

// QuicServerSession
QuicServerSession::InitialPacketResult QuicServerSession::Accept(
Expand Down Expand Up @@ -2376,6 +2394,11 @@ int QuicServerSession::VerifyPeerIdentity(const char* hostname) {
return VerifyPeerCertificate(ssl());
}

void QuicServerSession::MemoryInfo(MemoryTracker* tracker) const {
QuicSession::MemoryInfo(tracker);
tracker->TrackField("conn_closebuf", conn_closebuf_);
tracker->TrackField("ocsp_response", ocsp_response_);
}

// QuicClientSession

Expand Down Expand Up @@ -2888,6 +2911,11 @@ int QuicClientSession::VerifyPeerIdentity(const char* hostname) {
return 0;
}

void QuicClientSession::MemoryInfo(MemoryTracker* tracker) const {
QuicSession::MemoryInfo(tracker);
tracker->TrackField("hostname", hostname_);
}

// Static ngtcp2 callbacks are registered when ngtcp2 when a new ngtcp2_conn is
// created. These are static functions that, for the most part, simply defer to
// a QuicSession instance that is passed through as user_data.
Expand Down
8 changes: 6 additions & 2 deletions src/node_quic_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ class QuicSession : public AsyncWrap,
QuicSession* session_;
};

void MemoryInfo(MemoryTracker* tracker) const override;

private:
// Returns true if the QuicSession has entered the
// closing period following a call to ImmediateClose.
Expand Down Expand Up @@ -1063,7 +1065,8 @@ class QuicServerSession : public QuicSession {
const ngtcp2_cid* rcid() const { return &rcid_; }
ngtcp2_cid* pscid() { return &pscid_; }

void MemoryInfo(MemoryTracker* tracker) const override {}
void MemoryInfo(MemoryTracker* tracker) const override;

SET_MEMORY_INFO_NAME(QuicServerSession)
SET_SELF_SIZE(QuicServerSession)

Expand Down Expand Up @@ -1168,7 +1171,8 @@ class QuicClientSession : public QuicSession {

bool SendConnectionClose() override;

void MemoryInfo(MemoryTracker* tracker) const override {}
void MemoryInfo(MemoryTracker* tracker) const override;

SET_MEMORY_INFO_NAME(QuicClientSession)
SET_SELF_SIZE(QuicClientSession)

Expand Down
8 changes: 7 additions & 1 deletion src/node_quic_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ QuicSocket::~QuicSocket() {
}

void QuicSocket::MemoryInfo(MemoryTracker* tracker) const {
// TODO(@jasnell): Implement memory tracking information
tracker->TrackField("sessions", sessions_);
tracker->TrackField("dcid_to_scid", dcid_to_scid_);
tracker->TrackFieldWithSize("addr_counts",
addr_counts_.size() * (sizeof(sockaddr*) + sizeof(size_t)));
tracker->TrackField("validated_addrs", validated_addrs_);
tracker->TrackField("stats_buffer", stats_buffer_);
tracker->TrackFieldWithSize("current_ngtcp2_memory", current_ngtcp2_memory_);
}

void QuicSocket::AddSession(
Expand Down
8 changes: 8 additions & 0 deletions src/node_quic_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ BaseObjectPtr<QuicStream> QuicStream::New(
return stream;
}

void QuicStream::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("buffer", &streambuf_);
tracker->TrackField("data_rx_rate", data_rx_rate_);
tracker->TrackField("data_rx_size", data_rx_size_);
tracker->TrackField("data_rx_ack", data_rx_ack_);
tracker->TrackField("stats_buffer", stats_buffer_);
}

// JavaScript API
namespace {
void QuicStreamGetID(const FunctionCallbackInfo<Value>& args) {
Expand Down
4 changes: 1 addition & 3 deletions src/node_quic_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,7 @@ class QuicStream : public AsyncWrap, public StreamBase {

AsyncWrap* GetAsyncWrap() override { return this; }

void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackField("buffer", &streambuf_);
}
void MemoryInfo(MemoryTracker* tracker) const override;

SET_MEMORY_INFO_NAME(QuicStream)
SET_SELF_SIZE(QuicStream)
Expand Down
8 changes: 6 additions & 2 deletions src/node_quic_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ void IncrementStat(
// Simple timer wrapper that is used to implement the internals
// for idle and retransmission timeouts. Call Update to start or
// reset the timer; Stop to halt the timer.
class Timer {
class Timer final : public MemoryRetainer {
public:
explicit Timer(Environment* env, std::function<void()> fn)
: stopped_(false),
Expand All @@ -395,7 +395,7 @@ class Timer {
env->AddCleanupHook(CleanupHook, this);
}

~Timer() {
~Timer() override {
env_->RemoveCleanupHook(CleanupHook, this);
}

Expand Down Expand Up @@ -423,6 +423,10 @@ class Timer {

static void Free(Timer* timer);

SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(Timer)
SET_SELF_SIZE(Timer)

private:
static void OnTimeout(uv_timer_t* timer);
static void CleanupHook(void* data);
Expand Down
144 changes: 144 additions & 0 deletions test/pummel/test-heapdump-quic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
if (!common.hasQuic)
common.skip('missing quic');

const quic = require('quic');

const { recordState } = require('../common/heap');
const fixtures = require('../common/fixtures');
const key = fixtures.readKey('agent1-key.pem', 'binary');
const cert = fixtures.readKey('agent1-cert.pem', 'binary');
const ca = fixtures.readKey('ca1-cert.pem', 'binary');

{
const state = recordState();
state.validateSnapshotNodes('Node / QuicStream', []);
state.validateSnapshotNodes('Node / QuicSession', []);
state.validateSnapshotNodes('Node / QuicSocket', []);
}

const server = quic.createSocket({ port: 0, validateAddress: true });

server.listen({
key,
cert,
ca,
rejectUnauthorized: false,
maxCryptoBuffer: 4096,
alpn: 'meow'
});

server.on('session', common.mustCall((session) => {
session.on('secure', common.mustCall((servername, alpn, cipher) => {
// eslint-disable-next-line no-unused-vars
const stream = session.openStream({ halfOpen: false });

const state = recordState();

state.validateSnapshotNodes('Node / QuicSocket', [
{
children: [
{ node_name: 'QuicSocket', edge_name: 'wrapped' },
{ node_name: 'BigUint64Array', edge_name: 'stats_buffer' },
{ node_name: 'Node / sessions', edge_name: 'sessions' },
{ node_name: 'Node / dcid_to_scid', edge_name: 'dcid_to_scid' },
]
}
], { loose: true });

state.validateSnapshotNodes('Node / QuicStream', [
{
children: [
{ node_name: 'QuicStream', edge_name: 'wrapped' },
{ node_name: 'BigUint64Array', edge_name: 'stats_buffer' },
{ node_name: 'Node / QuicBuffer', edge_name: 'buffer' },
{ node_name: 'Node / HistogramBase', edge_name: 'data_rx_rate' },
{ node_name: 'Node / HistogramBase', edge_name: 'data_rx_size' },
{ node_name: 'Node / HistogramBase', edge_name: 'data_rx_ack' }
]
}
], { loose: true });

state.validateSnapshotNodes('Node / QuicBuffer', [
{
children: [
{ node_name: 'Node / length', edge_name: 'length' }
]
}
], { loose: true });

state.validateSnapshotNodes('Node / QuicServerSession', [
{
children: [
{ node_name: 'QuicServerSession', edge_name: 'wrapped' },
{ node_name: 'Node / rx_secret', edge_name: 'rx_secret' },
{ node_name: 'Node / tx_secret', edge_name: 'tx_secret' },
{ node_name: 'Node / HistogramBase', edge_name: 'crypto_rx_ack' },
{ node_name: 'Node / HistogramBase',
edge_name: 'crypto_handshake_rate' },
{ node_name: 'Node / Timer', edge_name: 'retransmit' },
{ node_name: 'Node / Timer', edge_name: 'idle' },
{ node_name: 'Node / QuicBuffer', edge_name: 'sendbuf' },
{ node_name: 'Node / QuicBuffer', edge_name: 'txbuf' },
{ node_name: 'Node / peer_handshake', edge_name: 'peer_handshake' },
{ node_name: 'Float64Array', edge_name: 'recovery_stats_buffer' },
{ node_name: 'BigUint64Array', edge_name: 'stats_buffer' },
{ node_name: 'Node / current_ngtcp2_memory',
edge_name: 'current_ngtcp2_memory' },
{ node_name: 'Node / streams', edge_name: 'streams' },
{ node_name: 'Node / QuicBuffer', edge_name: 'handshake' },
{ node_name: 'Node / std::basic_string', edge_name: 'alpn' },
{ node_name: 'Float64Array', edge_name: 'state' },
]
}
], { loose: true });

state.validateSnapshotNodes('Node / QuicClientSession', [
{
children: [
{ node_name: 'QuicClientSession', edge_name: 'wrapped' },
{ node_name: 'Node / rx_secret', edge_name: 'rx_secret' },
{ node_name: 'Node / tx_secret', edge_name: 'tx_secret' },
{ node_name: 'Node / HistogramBase', edge_name: 'crypto_rx_ack' },
{ node_name: 'Node / HistogramBase',
edge_name: 'crypto_handshake_rate' },
{ node_name: 'Node / Timer', edge_name: 'retransmit' },
{ node_name: 'Node / Timer', edge_name: 'idle' },
{ node_name: 'Node / QuicBuffer', edge_name: 'sendbuf' },
{ node_name: 'Node / QuicBuffer', edge_name: 'txbuf' },
{ node_name: 'Node / peer_handshake', edge_name: 'peer_handshake' },
{ node_name: 'Float64Array', edge_name: 'recovery_stats_buffer' },
{ node_name: 'BigUint64Array', edge_name: 'stats_buffer' },
{ node_name: 'Node / current_ngtcp2_memory',
edge_name: 'current_ngtcp2_memory' },
{ node_name: 'Node / QuicBuffer', edge_name: 'handshake' },
{ node_name: 'Node / std::basic_string', edge_name: 'alpn' },
{ node_name: 'Node / std::basic_string', edge_name: 'hostname' },
{ node_name: 'Float64Array', edge_name: 'state' },
]
}
], { loose: true });

session.destroy();
server.close();
}));
}));

server.on('ready', common.mustCall(() => {
const client = quic.createSocket({
port: 0,
client: {
key,
cert,
ca,
alpn: 'meow'
}
});

client.connect({
address: 'localhost',
port: server.address.port
}).on('close', common.mustCall(() => client.close()));
}));

0 comments on commit b12befc

Please sign in to comment.