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

Commit 84af079

Browse files
committed
src: refactor memory tracker implementation
Use a template class instead of virtual methods to allow inlining the subclass methods, as well as other minor cleanups. PR-URL: #126 Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent cda0d2c commit 84af079

8 files changed

+156
-112
lines changed

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@
622622
'src/node_internals.h',
623623
'src/node_main_instance.h',
624624
'src/node_mem.h',
625+
'src/node_mem-inl.h',
625626
'src/node_messaging.h',
626627
'src/node_metadata.h',
627628
'src/node_mutex.h',

src/node_mem-inl.h

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#ifndef SRC_NODE_MEM_INL_H_
2+
#define SRC_NODE_MEM_INL_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "node_mem.h"
7+
#include "node_internals.h"
8+
9+
namespace node {
10+
namespace mem {
11+
12+
template <typename Class, typename AllocatorStruct>
13+
AllocatorStruct NgLibMemoryManager<Class, AllocatorStruct>::MakeAllocator() {
14+
return AllocatorStruct {
15+
static_cast<void*>(static_cast<Class*>(this)),
16+
MallocImpl,
17+
FreeImpl,
18+
CallocImpl,
19+
ReallocImpl
20+
};
21+
}
22+
23+
template <typename Class, typename T>
24+
void* NgLibMemoryManager<Class, T>::ReallocImpl(void* ptr,
25+
size_t size,
26+
void* user_data) {
27+
Class* manager = static_cast<Class*>(user_data);
28+
29+
size_t previous_size = 0;
30+
char* original_ptr = nullptr;
31+
32+
// We prepend each allocated buffer with a size_t containing the full
33+
// size of the allocation.
34+
if (size > 0) size += sizeof(size_t);
35+
36+
if (ptr != nullptr) {
37+
// We are free()ing or re-allocating.
38+
original_ptr = static_cast<char*>(ptr) - sizeof(size_t);
39+
previous_size = *reinterpret_cast<size_t*>(original_ptr);
40+
// This means we called StopTracking() on this pointer before.
41+
if (previous_size == 0) {
42+
// Fall back to the standard Realloc() function.
43+
char* ret = UncheckedRealloc(original_ptr, size);
44+
if (ret != nullptr)
45+
ret += sizeof(size_t);
46+
return ret;
47+
}
48+
}
49+
50+
manager->CheckAllocatedSize(previous_size);
51+
52+
char* mem = UncheckedRealloc(original_ptr, size);
53+
54+
if (mem != nullptr) {
55+
// Adjust the memory info counter.
56+
// TODO(addaleax): Avoid the double bookkeeping we do with
57+
// current_nghttp2_memory_ + AdjustAmountOfExternalAllocatedMemory
58+
// and provide versions of our memory allocation utilities that take an
59+
// Environment*/Isolate* parameter and call the V8 method transparently.
60+
const int64_t new_size = size - previous_size;
61+
manager->IncreaseAllocatedSize(new_size);
62+
manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
63+
new_size);
64+
*reinterpret_cast<size_t*>(mem) = size;
65+
mem += sizeof(size_t);
66+
} else if (size == 0) {
67+
manager->DecreaseAllocatedSize(previous_size);
68+
manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
69+
-static_cast<int64_t>(previous_size));
70+
}
71+
return mem;
72+
}
73+
74+
template <typename Class, typename T>
75+
void* NgLibMemoryManager<Class, T>::MallocImpl(size_t size, void* user_data) {
76+
return ReallocImpl(nullptr, size, user_data);
77+
}
78+
79+
template <typename Class, typename T>
80+
void NgLibMemoryManager<Class, T>::FreeImpl(void* ptr, void* user_data) {
81+
if (ptr == nullptr) return;
82+
CHECK_NULL(ReallocImpl(ptr, 0, user_data));
83+
}
84+
85+
template <typename Class, typename T>
86+
void* NgLibMemoryManager<Class, T>::CallocImpl(size_t nmemb,
87+
size_t size,
88+
void* user_data) {
89+
size_t real_size = MultiplyWithOverflowCheck(nmemb, size);
90+
void* mem = MallocImpl(real_size, user_data);
91+
if (mem != nullptr)
92+
memset(mem, 0, real_size);
93+
return mem;
94+
}
95+
96+
template <typename Class, typename T>
97+
void NgLibMemoryManager<Class, T>::StopTrackingMemory(void* ptr) {
98+
size_t* original_ptr = reinterpret_cast<size_t*>(
99+
static_cast<char*>(ptr) - sizeof(size_t));
100+
Class* manager = static_cast<Class*>(this);
101+
manager->DecreaseAllocatedSize(*original_ptr);
102+
manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
103+
-static_cast<int64_t>(*original_ptr));
104+
*original_ptr = 0;
105+
}
106+
107+
} // namespace mem
108+
} // namespace node
109+
110+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
111+
112+
#endif // SRC_NODE_MEM_INL_H_

src/node_mem.h

+16-87
Original file line numberDiff line numberDiff line change
@@ -3,105 +3,34 @@
33

44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

6-
#include "node_internals.h"
6+
#include <stddef.h>
77

88
namespace node {
99
namespace mem {
1010

1111
// Both ngtcp2 and nghttp2 allow custom allocators that
1212
// follow exactly the same structure and behavior, but
1313
// use different struct names. To allow for code re-use,
14-
// the Allocator template class can be used for both.
14+
// the NgLibMemoryManager template class can be used for both.
1515

16-
struct Tracker {
17-
virtual void CheckAllocatedSize(size_t previous_size) = 0;
18-
virtual void IncrementAllocatedSize(size_t size) = 0;
19-
virtual void DecrementAllocatedSize(size_t size) = 0;
20-
};
21-
22-
inline static void* MemRealloc(
23-
void* ptr,
24-
size_t size,
25-
void* user_data) {
26-
27-
Tracker* tracker = static_cast<Tracker*>(user_data);
28-
29-
size_t previous_size = 0;
30-
char* original_ptr = nullptr;
31-
32-
if (size > 0) size += sizeof(size_t);
33-
34-
if (ptr != nullptr) {
35-
original_ptr = static_cast<char*>(ptr) - sizeof(size_t);
36-
previous_size = *reinterpret_cast<size_t*>(original_ptr);
37-
if (previous_size == 0) {
38-
char* ret = UncheckedRealloc(original_ptr, size);
39-
if (ret != nullptr)
40-
ret += sizeof(size_t);
41-
return ret;
42-
}
43-
}
44-
45-
tracker->CheckAllocatedSize(previous_size);
46-
47-
char* mem = UncheckedRealloc(original_ptr, size);
48-
49-
if (mem != nullptr) {
50-
tracker->IncrementAllocatedSize(size - previous_size);
51-
*reinterpret_cast<size_t*>(mem) = size;
52-
mem += sizeof(size_t);
53-
} else if (size == 0) {
54-
tracker->DecrementAllocatedSize(previous_size);
55-
}
56-
return mem;
57-
}
58-
59-
inline static void* MemMalloc(
60-
size_t size,
61-
void* user_data) {
62-
return MemRealloc(nullptr, size, user_data);
63-
}
64-
65-
inline static void MemFree(
66-
void* ptr,
67-
void* user_data) {
68-
if (ptr == nullptr) return;
69-
CHECK_NULL(MemRealloc(ptr, 0, user_data));
70-
}
71-
72-
inline static void* MemCalloc(
73-
size_t nmemb,
74-
size_t size,
75-
void* user_data) {
76-
size_t real_size = MultiplyWithOverflowCheck(nmemb, size);
77-
void* mem = MemMalloc(real_size, user_data);
78-
if (mem != nullptr)
79-
memset(mem, 0, real_size);
80-
return mem;
81-
}
16+
template <typename Class, typename AllocatorStructName>
17+
class NgLibMemoryManager {
18+
public:
19+
// Class needs to provide these methods:
20+
// void CheckAllocatedSize(size_t previous_size) const;
21+
// void IncreaseAllocatedSize(size_t size);
22+
// void DecreaseAllocatedSize(size_t size);
23+
// Environment* env() const;
8224

83-
inline static void MemStopTracking(Tracker* tracker, void* ptr) {
84-
size_t* original_ptr = reinterpret_cast<size_t*>(
85-
static_cast<char*>(ptr) - sizeof(size_t));
86-
tracker->DecrementAllocatedSize(*original_ptr);
87-
*original_ptr = 0;
88-
}
25+
AllocatorStructName MakeAllocator();
8926

90-
template <typename T>
91-
class Allocator {
92-
public:
93-
explicit inline Allocator(Tracker* user_data) :
94-
info_({
95-
user_data,
96-
MemMalloc,
97-
MemFree,
98-
MemCalloc,
99-
MemRealloc
100-
}) {}
27+
void StopTrackingMemory(void* ptr);
10128

102-
inline T* operator*() { return &info_; }
10329
private:
104-
T info_;
30+
static void* ReallocImpl(void* ptr, size_t size, void* user_data);
31+
static void* MallocImpl(size_t size, void* user_data);
32+
static void FreeImpl(void* ptr, void* user_data);
33+
static void* CallocImpl(size_t nmemb, size_t size, void* user_data);
10534
};
10635

10736
} // namespace mem

src/node_quic_session-inl.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ namespace node {
1111

1212
namespace quic {
1313

14-
void QuicSession::CheckAllocatedSize(size_t previous_size) {
14+
void QuicSession::CheckAllocatedSize(size_t previous_size) const {
1515
CHECK_GE(current_ngtcp2_memory_, previous_size);
1616
}
1717

18-
void QuicSession::IncrementAllocatedSize(size_t size) {
18+
void QuicSession::IncreaseAllocatedSize(size_t size) {
1919
current_ngtcp2_memory_ += size;
2020
}
2121

22-
void QuicSession::DecrementAllocatedSize(size_t size) {
22+
void QuicSession::DecreaseAllocatedSize(size_t size) {
2323
current_ngtcp2_memory_ -= size;
2424
}
2525

src/node_quic_session.cc

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "node_buffer.h"
77
#include "node_crypto.h"
88
#include "node_internals.h"
9+
#include "node_mem-inl.h"
910
#include "node_quic_crypto.h"
1011
#include "node_quic_session.h" // NOLINT(build/include_inline)
1112
#include "node_quic_session-inl.h"
@@ -182,7 +183,7 @@ QuicSession::QuicSession(
182183
idle_(new Timer(socket->env(), [this]() { OnIdleTimeout(); })),
183184
retransmit_(new Timer(socket->env(), [this]() { MaybeTimeout(); })),
184185
state_(env()->isolate(), IDX_QUIC_SESSION_STATE_COUNT),
185-
allocator_(this),
186+
alloc_info_(MakeAllocator()),
186187
crypto_rx_ack_(
187188
HistogramBase::New(
188189
socket->env(),
@@ -2013,7 +2014,7 @@ void QuicServerSession::Init(
20132014
version,
20142015
&callbacks,
20152016
*cfg,
2016-
*allocator_,
2017+
&alloc_info_,
20172018
static_cast<QuicSession*>(this)), 0);
20182019

20192020
if (ocid)
@@ -2543,7 +2544,7 @@ bool QuicClientSession::Init(
25432544
version,
25442545
&callbacks,
25452546
*config,
2546-
*allocator_,
2547+
&alloc_info_,
25472548
static_cast<QuicSession*>(this)), 0);
25482549

25492550
connection_.reset(conn);

src/node_quic_session.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ enum QuicSessionState : int {
183183
// a QuicSession object.
184184
class QuicSession : public AsyncWrap,
185185
public std::enable_shared_from_this<QuicSession>,
186-
public mem::Tracker {
186+
public mem::NgLibMemoryManager<QuicSession, ngtcp2_mem> {
187187
public:
188188
static const int kInitialClientBufferLength = 4096;
189189

@@ -338,10 +338,10 @@ class QuicSession : public AsyncWrap,
338338
virtual bool SendConnectionClose() = 0;
339339
virtual int TLSHandshake_Initial() = 0;
340340

341-
// Implementation for mem::Tracker
342-
inline void CheckAllocatedSize(size_t previous_size) override;
343-
inline void IncrementAllocatedSize(size_t size) override;
344-
inline void DecrementAllocatedSize(size_t size) override;
341+
// Implementation for mem::NgLibMemoryManager
342+
inline void CheckAllocatedSize(size_t previous_size) const;
343+
inline void IncreaseAllocatedSize(size_t size);
344+
inline void DecreaseAllocatedSize(size_t size);
345345

346346
// Tracks whether or not we are currently within an ngtcp2 callback
347347
// function. Certain ngtcp2 APIs are not supposed to be called when
@@ -876,7 +876,7 @@ class QuicSession : public AsyncWrap,
876876

877877
AliasedFloat64Array state_;
878878

879-
mem::Allocator<ngtcp2_mem> allocator_;
879+
ngtcp2_mem alloc_info_;
880880

881881
struct session_stats {
882882
// The timestamp at which the session was created

src/node_quic_socket.cc

+7-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "node.h"
66
#include "node_crypto.h"
77
#include "node_internals.h"
8+
#include "node_mem-inl.h"
89
#include "node_quic_crypto.h"
910
#include "node_quic_session-inl.h"
1011
#include "node_quic_socket.h"
@@ -83,7 +84,8 @@ QuicSocket::QuicSocket(
8384
stats_buffer_(
8485
env->isolate(),
8586
sizeof(socket_stats_) / sizeof(uint64_t),
86-
reinterpret_cast<uint64_t*>(&socket_stats_)) {
87+
reinterpret_cast<uint64_t*>(&socket_stats_)),
88+
alloc_info_(MakeAllocator()) {
8789
CHECK_EQ(uv_udp_init(env->event_loop(), &handle_), 0);
8890
Debug(this, "New QuicSocket created.");
8991

@@ -486,8 +488,6 @@ void QuicSocket::SendInitialConnectionClose(
486488
ngtcp2_settings settings;
487489
ngtcp2_settings_default(&settings);
488490

489-
mem::Allocator<ngtcp2_mem> allocator(this);
490-
491491
ngtcp2_conn* conn;
492492
ngtcp2_conn_server_new(
493493
&conn,
@@ -497,7 +497,7 @@ void QuicSocket::SendInitialConnectionClose(
497497
version,
498498
&callbacks,
499499
&settings,
500-
*allocator,
500+
&alloc_info_,
501501
nullptr);
502502

503503
SendWrapStack* req =
@@ -1011,19 +1011,18 @@ void QuicSocket::SetDiagnosticPacketLoss(double rx, double tx) {
10111011
tx_loss_ = tx;
10121012
}
10131013

1014-
inline void QuicSocket::CheckAllocatedSize(size_t previous_size) {
1014+
void QuicSocket::CheckAllocatedSize(size_t previous_size) const {
10151015
CHECK_GE(current_ngtcp2_memory_, previous_size);
10161016
}
10171017

1018-
inline void QuicSocket::IncrementAllocatedSize(size_t size) {
1018+
void QuicSocket::IncreaseAllocatedSize(size_t size) {
10191019
current_ngtcp2_memory_ += size;
10201020
}
10211021

1022-
inline void QuicSocket::DecrementAllocatedSize(size_t size) {
1022+
void QuicSocket::DecreaseAllocatedSize(size_t size) {
10231023
current_ngtcp2_memory_ -= size;
10241024
}
10251025

1026-
10271026
// JavaScript API
10281027
namespace {
10291028
void NewQuicSocket(const FunctionCallbackInfo<Value>& args) {

0 commit comments

Comments
 (0)