GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: memory_tracker-inl.h Lines: 127 147 86.4 %
Date: 2022-12-07 04:23:16 Branches: 44 66 66.7 %

Line Branch Exec Source
1
#ifndef SRC_MEMORY_TRACKER_INL_H_
2
#define SRC_MEMORY_TRACKER_INL_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "memory_tracker.h"
7
8
namespace node {
9
10
// Fallback edge_name if node_name is not available, or "" if edge_name
11
// is not available either.
12
3008
inline const char* GetNodeName(const char* node_name, const char* edge_name) {
13
3008
  if (node_name != nullptr) {
14
2816
    return node_name;
15
  }
16
192
  if (edge_name != nullptr) {
17
192
    return edge_name;
18
  }
19
  return "";
20
}
21
22
class MemoryRetainerNode : public v8::EmbedderGraph::Node {
23
 public:
24
1481
  inline MemoryRetainerNode(MemoryTracker* tracker,
25
                            const MemoryRetainer* retainer)
26
1481
      : retainer_(retainer) {
27
1481
    CHECK_NOT_NULL(retainer_);
28
1481
    v8::HandleScope handle_scope(tracker->isolate());
29
1481
    v8::Local<v8::Object> obj = retainer_->WrappedObject();
30
1481
    if (!obj.IsEmpty()) wrapper_node_ = tracker->graph()->V8Node(obj);
31
32
1481
    name_ = retainer_->MemoryInfoName();
33
1481
    size_ = retainer_->SelfSize();
34
1481
    detachedness_ = retainer_->GetDetachedness();
35
1481
  }
36
37
3008
  inline MemoryRetainerNode(MemoryTracker* tracker,
38
                            const char* name,
39
                            size_t size,
40
                            bool is_root_node = false)
41
3008
      : retainer_(nullptr) {
42
3008
    name_ = name;
43
3008
    size_ = size;
44
3008
    is_root_node_ = is_root_node;
45
3008
  }
46
47
4489
  const char* Name() override { return name_.c_str(); }
48
5136
  const char* NamePrefix() override { return "Node /"; }
49
4489
  size_t SizeInBytes() override { return size_; }
50
  // TODO(addaleax): Merging this with the "official" WrapperNode() method
51
  // seems to lose accuracy, e.g. SizeInBytes() is disregarded.
52
  // Figure out whether to do anything about that.
53
3433
  Node* JSWrapperNode() { return wrapper_node_; }
54
55
8331
  bool IsRootNode() override {
56
8331
    if (retainer_ != nullptr) {
57
2695
      return retainer_->IsRootNode();
58
    }
59
5636
    return is_root_node_;
60
  }
61
3842
  v8::EmbedderGraph::Node::Detachedness GetDetachedness() override {
62
3842
    return detachedness_;
63
  }
64
65
 private:
66
  friend class MemoryTracker;
67
68
  // If retainer_ is not nullptr, then it must have a wrapper_node_,
69
  // and we have
70
  // name_ == retainer_->MemoryInfoName()
71
  // size_ == retainer_->SelfSize()
72
  // is_root_node_ == retainer_->IsRootNode()
73
  const MemoryRetainer* retainer_;
74
  Node* wrapper_node_ = nullptr;
75
76
  // Otherwise (retainer == nullptr), we set these fields in an ad-hoc way
77
  bool is_root_node_ = false;
78
  std::string name_;
79
  size_t size_ = 0;
80
  v8::EmbedderGraph::Node::Detachedness detachedness_ =
81
      v8::EmbedderGraph::Node::Detachedness::kUnknown;
82
};
83
84
2840
void MemoryTracker::TrackFieldWithSize(const char* edge_name,
85
                                       size_t size,
86
                                       const char* node_name) {
87
2840
  if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name);
88
2840
}
89
90
void MemoryTracker::TrackInlineFieldWithSize(const char* edge_name,
91
                                             size_t size,
92
                                             const char* node_name) {
93
  if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name);
94
  CHECK(CurrentNode());
95
  CurrentNode()->size_ -= size;
96
}
97
98
191
void MemoryTracker::TrackField(const char* edge_name,
99
                               const MemoryRetainer& value,
100
                               const char* node_name) {
101
191
  TrackField(edge_name, &value);
102
191
}
103
104
510
void MemoryTracker::TrackField(const char* edge_name,
105
                               const MemoryRetainer* value,
106
                               const char* node_name) {
107
510
  if (value == nullptr) return;
108
510
  auto it = seen_.find(value);
109
510
  if (it != seen_.end()) {
110
42
    graph_->AddEdge(CurrentNode(), it->second, edge_name);
111
  } else {
112
468
    Track(value, edge_name);
113
  }
114
}
115
116
template <typename T, typename D>
117
141
void MemoryTracker::TrackField(const char* edge_name,
118
                               const std::unique_ptr<T, D>& value,
119
                               const char* node_name) {
120
141
  if (value.get() == nullptr) {
121
2
    return;
122
  }
123
139
  TrackField(edge_name, value.get(), node_name);
124
}
125
126
template <typename T>
127
119
void MemoryTracker::TrackField(const char* edge_name,
128
                               const std::shared_ptr<T>& value,
129
                               const char* node_name) {
130
119
  if (value.get() == nullptr) {
131
    return;
132
  }
133
119
  TrackField(edge_name, value.get(), node_name);
134
}
135
136
template <typename T, bool kIsWeak>
137
9
void MemoryTracker::TrackField(const char* edge_name,
138
                               const BaseObjectPtrImpl<T, kIsWeak>& value,
139
                               const char* node_name) {
140

9
  if (value.get() == nullptr || kIsWeak) return;
141
9
  TrackField(edge_name, value.get(), node_name);
142
}
143
144
template <typename T, typename Iterator>
145
1035
void MemoryTracker::TrackField(const char* edge_name,
146
                               const T& value,
147
                               const char* node_name,
148
                               const char* element_name,
149
                               bool subtract_from_self) {
150
  // If the container is empty, the size has been accounted into the parent's
151
  // self size
152
1035
  if (value.begin() == value.end()) return;
153
  // Fall back to edge name if node names are not provided
154

327
  if (CurrentNode() != nullptr && subtract_from_self) {
155
    // Shift the self size of this container out to a separate node
156
327
    CurrentNode()->size_ -= sizeof(T);
157
  }
158
327
  PushNode(GetNodeName(node_name, edge_name), sizeof(T), edge_name);
159
10629
  for (Iterator it = value.begin(); it != value.end(); ++it) {
160
    // Use nullptr as edge names so the elements appear as indexed properties
161
10302
    TrackField(nullptr, *it, element_name);
162
  }
163
327
  PopNode();
164
}
165
166
template <typename T>
167
16
void MemoryTracker::TrackField(const char* edge_name,
168
                               const std::queue<T>& value,
169
                               const char* node_name,
170
                               const char* element_name) {
171
  struct ContainerGetter : public std::queue<T> {
172
8
    static const typename std::queue<T>::container_type& Get(
173
        const std::queue<T>& value) {
174
8
      return value.*&ContainerGetter::c;
175
    }
176
  };
177
178
16
  const auto& container = ContainerGetter::Get(value);
179
16
  TrackField(edge_name, container, node_name, element_name);
180
}
181
182
template <typename T, typename test_for_number, typename dummy>
183
79
void MemoryTracker::TrackField(const char* edge_name,
184
                               const T& value,
185
                               const char* node_name) {
186
  // For numbers, creating new nodes is not worth the overhead.
187
79
  CurrentNode()->size_ += sizeof(T);
188
79
}
189
190
template <typename T, typename U>
191
void MemoryTracker::TrackField(const char* edge_name,
192
                               const std::pair<T, U>& value,
193
                               const char* node_name) {
194
  PushNode(node_name == nullptr ? "pair" : node_name,
195
           sizeof(const std::pair<T, U>),
196
           edge_name);
197
  // TODO(joyeecheung): special case if one of these is a number type
198
  // that meets the test_for_number trait so that their sizes don't get
199
  // merged into the pair node
200
  TrackField("first", value.first);
201
  TrackField("second", value.second);
202
  PopNode();
203
}
204
205
template <typename T>
206
2733
void MemoryTracker::TrackField(const char* edge_name,
207
                               const std::basic_string<T>& value,
208
                               const char* node_name) {
209
2733
  TrackFieldWithSize(edge_name, value.size() * sizeof(T), "std::basic_string");
210
2733
}
211
212
template <typename T>
213
2146
void MemoryTracker::TrackField(const char* edge_name,
214
                               const v8::Eternal<T>& value,
215
                               const char* node_name) {
216
2146
  TrackField(edge_name, value.Get(isolate_));
217
2146
}
218
219
template <typename T>
220
205
void MemoryTracker::TrackField(const char* edge_name,
221
                               const v8::PersistentBase<T>& value,
222
                               const char* node_name) {
223
205
  if (value.IsWeak()) return;
224
410
  TrackField(edge_name, value.Get(isolate_));
225
}
226
227
template <typename T>
228
31348
void MemoryTracker::TrackField(const char* edge_name,
229
                               const v8::Local<T>& value,
230
                               const char* node_name) {
231
31348
  if (!value.IsEmpty())
232
29594
    graph_->AddEdge(CurrentNode(), graph_->V8Node(value), edge_name);
233
31348
}
234
235
template <typename T>
236
void MemoryTracker::TrackField(const char* edge_name,
237
                               const MallocedBuffer<T>& value,
238
                               const char* node_name) {
239
  TrackFieldWithSize(edge_name, value.size, "MallocedBuffer");
240
}
241
242
void MemoryTracker::TrackField(const char* edge_name,
243
                               const v8::BackingStore* value,
244
                               const char* node_name) {
245
  TrackFieldWithSize(edge_name, value->ByteLength(), "BackingStore");
246
}
247
248
void MemoryTracker::TrackField(const char* name,
249
                               const uv_buf_t& value,
250
                               const char* node_name) {
251
  TrackFieldWithSize(name, value.len, "uv_buf_t");
252
}
253
254
void MemoryTracker::TrackField(const char* name,
255
                               const uv_timer_t& value,
256
                               const char* node_name) {
257
  TrackFieldWithSize(name, sizeof(value), "uv_timer_t");
258
}
259
260
void MemoryTracker::TrackField(const char* name,
261
                               const uv_async_t& value,
262
                               const char* node_name) {
263
  TrackFieldWithSize(name, sizeof(value), "uv_async_t");
264
}
265
266
void MemoryTracker::TrackInlineField(const char* name,
267
                                     const uv_async_t& value,
268
                                     const char* node_name) {
269
  TrackInlineFieldWithSize(name, sizeof(value), "uv_async_t");
270
}
271
272
template <class NativeT, class V8T>
273
968
void MemoryTracker::TrackField(const char* name,
274
                               const AliasedBufferBase<NativeT, V8T>& value,
275
                               const char* node_name) {
276
968
  TrackField(name, value.GetJSArray(), "AliasedBuffer");
277
968
}
278
279
2457
void MemoryTracker::Track(const MemoryRetainer* retainer,
280
                          const char* edge_name) {
281
2457
  v8::HandleScope handle_scope(isolate_);
282
2457
  auto it = seen_.find(retainer);
283
2457
  if (it != seen_.end()) {
284
976
    if (CurrentNode() != nullptr) {
285
976
      graph_->AddEdge(CurrentNode(), it->second, edge_name);
286
    }
287
976
    return;  // It has already been tracked, no need to call MemoryInfo again
288
  }
289
1481
  MemoryRetainerNode* n = PushNode(retainer, edge_name);
290
1481
  retainer->MemoryInfo(this);
291
1481
  CHECK_EQ(CurrentNode(), n);
292
1481
  CHECK_NE(n->size_, 0);
293
1481
  PopNode();
294
}
295
296
void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer,
297
                                     const char* edge_name) {
298
  Track(retainer, edge_name);
299
  CHECK(CurrentNode());
300
  CurrentNode()->size_ -= retainer->SelfSize();
301
}
302
303
27825
MemoryRetainerNode* MemoryTracker::CurrentNode() const {
304
27825
  if (node_stack_.empty()) return nullptr;
305
27788
  return node_stack_.top();
306
}
307
308
1481
MemoryRetainerNode* MemoryTracker::AddNode(const MemoryRetainer* retainer,
309
                                           const char* edge_name) {
310
1481
  auto it = seen_.find(retainer);
311
1481
  if (it != seen_.end()) {
312
    return it->second;
313
  }
314
315
1481
  MemoryRetainerNode* n = new MemoryRetainerNode(this, retainer);
316
1481
  graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n));
317
1481
  seen_[retainer] = n;
318
1481
  if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name);
319
320
1481
  if (n->JSWrapperNode() != nullptr) {
321
976
    graph_->AddEdge(n, n->JSWrapperNode(), "wrapped");
322
976
    graph_->AddEdge(n->JSWrapperNode(), n, "wrapper");
323
  }
324
325
1481
  return n;
326
}
327
328
3008
MemoryRetainerNode* MemoryTracker::AddNode(const char* node_name,
329
                                           size_t size,
330
                                           const char* edge_name) {
331
3008
  MemoryRetainerNode* n = new MemoryRetainerNode(this, node_name, size);
332
3008
  graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n));
333
334
3008
  if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name);
335
336
3008
  return n;
337
}
338
339
1481
MemoryRetainerNode* MemoryTracker::PushNode(const MemoryRetainer* retainer,
340
                                            const char* edge_name) {
341
1481
  MemoryRetainerNode* n = AddNode(retainer, edge_name);
342
1481
  node_stack_.push(n);
343
1481
  return n;
344
}
345
346
182
MemoryRetainerNode* MemoryTracker::PushNode(const char* node_name,
347
                                            size_t size,
348
                                            const char* edge_name) {
349
182
  MemoryRetainerNode* n = AddNode(node_name, size, edge_name);
350
182
  node_stack_.push(n);
351
182
  return n;
352
}
353
354
1663
void MemoryTracker::PopNode() {
355
1663
  node_stack_.pop();
356
1663
}
357
358
}  // namespace node
359
360
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
361
362
#endif  // SRC_MEMORY_TRACKER_INL_H_