GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/memory_tracker-inl.h Lines: 119 146 81.5 %
Date: 2020-08-17 22:13:26 Branches: 68 142 47.9 %

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
1504
inline const char* GetNodeName(const char* node_name, const char* edge_name) {
13
1504
  if (node_name != nullptr) {
14
1414
    return node_name;
15
  }
16
90
  if (edge_name != nullptr) {
17
90
    return edge_name;
18
  }
19
  return "";
20
}
21
22
3886
class MemoryRetainerNode : public v8::EmbedderGraph::Node {
23
 public:
24
439
  inline MemoryRetainerNode(MemoryTracker* tracker,
25
                                     const MemoryRetainer* retainer)
26
439
      : retainer_(retainer) {
27
439
    CHECK_NOT_NULL(retainer_);
28
878
    v8::HandleScope handle_scope(tracker->isolate());
29
439
    v8::Local<v8::Object> obj = retainer_->WrappedObject();
30
783
    if (!obj.IsEmpty()) wrapper_node_ = tracker->graph()->V8Node(obj);
31
32
439
    name_ = retainer_->MemoryInfoName();
33
439
    size_ = retainer_->SelfSize();
34
439
  }
35
36
1504
  inline MemoryRetainerNode(MemoryTracker* tracker,
37
                                     const char* name,
38
                                     size_t size,
39
                                     bool is_root_node = false)
40
1504
      : retainer_(nullptr) {
41
1504
    name_ = name;
42
1504
    size_ = size;
43
1504
    is_root_node_ = is_root_node;
44
1504
  }
45
46
1943
  const char* Name() override { return name_.c_str(); }
47
1943
  const char* NamePrefix() override { return "Node /"; }
48
1943
  size_t SizeInBytes() override { return size_; }
49
  // TODO(addaleax): Merging this with the "official" WrapperNode() method
50
  // seems to lose accuracy, e.g. SizeInBytes() is disregarded.
51
  // Figure out whether to do anything about that.
52
1127
  Node* JSWrapperNode() { return wrapper_node_; }
53
54
3886
  bool IsRootNode() override {
55
3886
    if (retainer_ != nullptr) {
56
878
      return retainer_->IsRootNode();
57
    }
58
3008
    return is_root_node_;
59
  }
60
61
 private:
62
  friend class MemoryTracker;
63
64
  // If retainer_ is not nullptr, then it must have a wrapper_node_,
65
  // and we have
66
  // name_ == retainer_->MemoryInfoName()
67
  // size_ == retainer_->SelfSize()
68
  // is_root_node_ == retainer_->IsRootNode()
69
  const MemoryRetainer* retainer_;
70
  Node* wrapper_node_ = nullptr;
71
72
  // Otherwise (retainer == nullptr), we set these fields in an ad-hoc way
73
  bool is_root_node_ = false;
74
  std::string name_;
75
  size_t size_ = 0;
76
};
77
78
1449
void MemoryTracker::TrackFieldWithSize(const char* edge_name,
79
                                       size_t size,
80
                                       const char* node_name) {
81
1449
  if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name);
82
1449
}
83
84
void MemoryTracker::TrackInlineFieldWithSize(const char* edge_name,
85
                                             size_t size,
86
                                             const char* node_name) {
87
  if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name);
88
  CHECK(CurrentNode());
89
  CurrentNode()->size_ -= size;
90
}
91
92
57
void MemoryTracker::TrackField(const char* edge_name,
93
                               const MemoryRetainer& value,
94
                               const char* node_name) {
95
57
  TrackField(edge_name, &value);
96
57
}
97
98
80
void MemoryTracker::TrackField(const char* edge_name,
99
                               const MemoryRetainer* value,
100
                               const char* node_name) {
101
80
  if (value == nullptr) return;
102
80
  auto it = seen_.find(value);
103
80
  if (it != seen_.end()) {
104
4
    graph_->AddEdge(CurrentNode(), it->second, edge_name);
105
  } else {
106
76
    Track(value, edge_name);
107
  }
108
}
109
110
template <typename T, typename D>
111
2
void MemoryTracker::TrackField(const char* edge_name,
112
                               const std::unique_ptr<T, D>& value,
113
                               const char* node_name) {
114

2
  if (value.get() == nullptr) {
115
2
    return;
116
  }
117
  TrackField(edge_name, value.get(), node_name);
118
}
119
120
template <typename T>
121
void MemoryTracker::TrackField(const char* edge_name,
122
                               const std::shared_ptr<T>& value,
123
                               const char* node_name) {
124
  if (value.get() == nullptr) {
125
    return;
126
  }
127
  TrackField(edge_name, value.get(), node_name);
128
}
129
130
template <typename T, bool kIsWeak>
131
4
void MemoryTracker::TrackField(const char* edge_name,
132
                               const BaseObjectPtrImpl<T, kIsWeak>& value,
133
                               const char* node_name) {
134



4
  if (value.get() == nullptr || kIsWeak) return;
135
4
  TrackField(edge_name, value.get(), node_name);
136
}
137
138
template <typename T, typename Iterator>
139
303
void MemoryTracker::TrackField(const char* edge_name,
140
                               const T& value,
141
                               const char* node_name,
142
                               const char* element_name,
143
                               bool subtract_from_self) {
144
  // If the container is empty, the size has been accounted into the parent's
145
  // self size
146



303
  if (value.begin() == value.end()) return;
147
  // Fall back to edge name if node names are not provided
148









67
  if (CurrentNode() != nullptr && subtract_from_self) {
149
    // Shift the self size of this container out to a separate node
150
67
    CurrentNode()->size_ -= sizeof(T);
151
  }
152
67
  PushNode(GetNodeName(node_name, edge_name), sizeof(T), edge_name);
153



2543
  for (Iterator it = value.begin(); it != value.end(); ++it) {
154
    // Use nullptr as edge names so the elements appear as indexed properties
155
2476
    TrackField(nullptr, *it, element_name);
156
  }
157
67
  PopNode();
158
}
159
160
template <typename T>
161
8
void MemoryTracker::TrackField(const char* edge_name,
162
                               const std::queue<T>& value,
163
                               const char* node_name,
164
                               const char* element_name) {
165
  struct ContainerGetter : public std::queue<T> {
166
8
    static const typename std::queue<T>::container_type& Get(
167
        const std::queue<T>& value) {
168
8
      return value.*&ContainerGetter::c;
169
    }
170
  };
171
172
8
  const auto& container = ContainerGetter::Get(value);
173
8
  TrackField(edge_name, container, node_name, element_name);
174
8
}
175
176
template <typename T, typename test_for_number, typename dummy>
177
79
void MemoryTracker::TrackField(const char* edge_name,
178
                               const T& value,
179
                               const char* node_name) {
180
  // For numbers, creating new nodes is not worth the overhead.
181
79
  CurrentNode()->size_ += sizeof(T);
182
79
}
183
184
template <typename T, typename U>
185
void MemoryTracker::TrackField(const char* edge_name,
186
                               const std::pair<T, U>& value,
187
                               const char* node_name) {
188
  PushNode(node_name == nullptr ? "pair" : node_name,
189
           sizeof(const std::pair<T, U>),
190
           edge_name);
191
  // TODO(joyeecheung): special case if one of these is a number type
192
  // that meets the test_for_number trait so that their sizes don't get
193
  // merged into the pair node
194
  TrackField("first", value.first);
195
  TrackField("second", value.second);
196
  PopNode();
197
}
198
199
template <typename T>
200
1367
void MemoryTracker::TrackField(const char* edge_name,
201
                               const std::basic_string<T>& value,
202
                               const char* node_name) {
203
1367
  TrackFieldWithSize(edge_name, value.size() * sizeof(T), "std::basic_string");
204
1367
}
205
206
template <typename T>
207
1026
void MemoryTracker::TrackField(const char* edge_name,
208
                               const v8::Eternal<T>& value,
209
                               const char* node_name) {
210
2052
  TrackField(edge_name, value.Get(isolate_));
211
1026
}
212
213
template <typename T>
214
25
void MemoryTracker::TrackField(const char* edge_name,
215
                               const v8::PersistentBase<T>& value,
216
                               const char* node_name) {
217

25
  if (value.IsWeak()) return;
218
50
  TrackField(edge_name, value.Get(isolate_));
219
}
220
221
template <typename T>
222
6897
void MemoryTracker::TrackField(const char* edge_name,
223
                               const v8::Local<T>& value,
224
                               const char* node_name) {
225




6897
  if (!value.IsEmpty())
226
13038
    graph_->AddEdge(CurrentNode(), graph_->V8Node(value), edge_name);
227
6897
}
228
229
template <typename T>
230
void MemoryTracker::TrackField(const char* edge_name,
231
                               const MallocedBuffer<T>& value,
232
                               const char* node_name) {
233
  TrackFieldWithSize(edge_name, value.size, "MallocedBuffer");
234
}
235
236
void MemoryTracker::TrackField(const char* edge_name,
237
                               const v8::BackingStore* value,
238
                               const char* node_name) {
239
  TrackFieldWithSize(edge_name, value->ByteLength(), "BackingStore");
240
}
241
242
void MemoryTracker::TrackField(const char* name,
243
                               const uv_buf_t& value,
244
                               const char* node_name) {
245
  TrackFieldWithSize(name, value.len, "uv_buf_t");
246
}
247
248
void MemoryTracker::TrackField(const char* name,
249
                               const uv_timer_t& value,
250
                               const char* node_name) {
251
  TrackFieldWithSize(name, sizeof(value), "uv_timer_t");
252
}
253
254
void MemoryTracker::TrackField(const char* name,
255
                               const uv_async_t& value,
256
                               const char* node_name) {
257
  TrackFieldWithSize(name, sizeof(value), "uv_async_t");
258
}
259
260
void MemoryTracker::TrackInlineField(const char* name,
261
                                     const uv_async_t& value,
262
                                     const char* node_name) {
263
  TrackInlineFieldWithSize(name, sizeof(value), "uv_async_t");
264
}
265
266
template <class NativeT, class V8T>
267
222
void MemoryTracker::TrackField(const char* name,
268
                               const AliasedBufferBase<NativeT, V8T>& value,
269
                               const char* node_name) {
270
222
  TrackField(name, value.GetJSArray(), "AliasedBuffer");
271
222
}
272
273
439
void MemoryTracker::Track(const MemoryRetainer* retainer,
274
                          const char* edge_name) {
275
878
  v8::HandleScope handle_scope(isolate_);
276
439
  auto it = seen_.find(retainer);
277
439
  if (it != seen_.end()) {
278
    if (CurrentNode() != nullptr) {
279
      graph_->AddEdge(CurrentNode(), it->second, edge_name);
280
    }
281
    return;  // It has already been tracked, no need to call MemoryInfo again
282
  }
283
439
  MemoryRetainerNode* n = PushNode(retainer, edge_name);
284
439
  retainer->MemoryInfo(this);
285
439
  CHECK_EQ(CurrentNode(), n);
286
439
  CHECK_NE(n->size_, 0);
287
439
  PopNode();
288
}
289
290
void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer,
291
                                     const char* edge_name) {
292
  Track(retainer, edge_name);
293
  CHECK(CurrentNode());
294
  CurrentNode()->size_ -= retainer->SelfSize();
295
}
296
297
10698
MemoryRetainerNode* MemoryTracker::CurrentNode() const {
298
10698
  if (node_stack_.empty()) return nullptr;
299
10335
  return node_stack_.top();
300
}
301
302
439
MemoryRetainerNode* MemoryTracker::AddNode(const MemoryRetainer* retainer,
303
                                           const char* edge_name) {
304
439
  auto it = seen_.find(retainer);
305
439
  if (it != seen_.end()) {
306
    return it->second;
307
  }
308
309
439
  MemoryRetainerNode* n = new MemoryRetainerNode(this, retainer);
310
439
  graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n));
311
439
  seen_[retainer] = n;
312
439
  if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name);
313
314
439
  if (n->JSWrapperNode() != nullptr) {
315
344
    graph_->AddEdge(n, n->JSWrapperNode(), "wrapped");
316
344
    graph_->AddEdge(n->JSWrapperNode(), n, "wrapper");
317
  }
318
319
439
  return n;
320
}
321
322
1504
MemoryRetainerNode* MemoryTracker::AddNode(const char* node_name,
323
                                           size_t size,
324
                                           const char* edge_name) {
325
1504
  MemoryRetainerNode* n = new MemoryRetainerNode(this, node_name, size);
326
1504
  graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n));
327
328
1504
  if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name);
329
330
1504
  return n;
331
}
332
333
439
MemoryRetainerNode* MemoryTracker::PushNode(const MemoryRetainer* retainer,
334
                                            const char* edge_name) {
335
439
  MemoryRetainerNode* n = AddNode(retainer, edge_name);
336
439
  node_stack_.push(n);
337
439
  return n;
338
}
339
340
67
MemoryRetainerNode* MemoryTracker::PushNode(const char* node_name,
341
                                            size_t size,
342
                                            const char* edge_name) {
343
67
  MemoryRetainerNode* n = AddNode(node_name, size, edge_name);
344
67
  node_stack_.push(n);
345
67
  return n;
346
}
347
348
506
void MemoryTracker::PopNode() {
349
506
  node_stack_.pop();
350
506
}
351
352
}  // namespace node
353
354
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
355
356
#endif  // SRC_MEMORY_TRACKER_INL_H_