Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/memory_tracker-inl.h
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 #include "util-inl.h" 8 9 namespace node { 10 11 // Fallback edge_name if node_name is not available, or "" if edge_name 12 // is not available either. 13 inline const char* GetNodeName(const char* node_name, const char* edge_name) { 14 if (node_name != nullptr) { 15 return node_name; 16 } 17 if (edge_name != nullptr) { 18 return edge_name; 19 } 20 return ""; 21 } 22 23 class MemoryRetainerNode : public v8::EmbedderGraph::Node { 24 public: 25 inline MemoryRetainerNode(MemoryTracker* tracker, 26 const MemoryRetainer* retainer) 27 : retainer_(retainer) { 28 CHECK_NOT_NULL(retainer_); 29 v8::HandleScope handle_scope(tracker->isolate()); 30 v8::Local<v8::Object> obj = retainer_->WrappedObject(); 31 if (!obj.IsEmpty()) 32 wrapper_node_ = tracker->graph()->V8Node(obj.As<v8::Value>()); 33 34 name_ = retainer_->MemoryInfoName(); 35 size_ = retainer_->SelfSize(); 36 detachedness_ = retainer_->GetDetachedness(); 37 } 38 39 inline MemoryRetainerNode(MemoryTracker* tracker, 40 const char* name, 41 size_t size, 42 bool is_root_node = false) 43 : retainer_(nullptr) { 44 name_ = name; 45 size_ = size; 46 is_root_node_ = is_root_node; 47 } 48 49 const char* Name() override { return name_; } 50 const char* NamePrefix() override { return "Node /"; } 51 size_t SizeInBytes() override { return size_; } 52 // TODO(addaleax): Merging this with the "official" WrapperNode() method 53 // seems to lose accuracy, e.g. SizeInBytes() is disregarded. 54 // Figure out whether to do anything about that. 55 Node* JSWrapperNode() { return wrapper_node_; } 56 57 bool IsRootNode() override { 58 if (retainer_ != nullptr) { 59 return retainer_->IsRootNode(); 60 } 61 return is_root_node_; 62 } 63 v8::EmbedderGraph::Node::Detachedness GetDetachedness() override { 64 return detachedness_; 65 } 66 67 private: 68 friend class MemoryTracker; 69 70 // If retainer_ is not nullptr, then it must have a wrapper_node_, 71 // and we have 72 // name_ == retainer_->MemoryInfoName() 73 // size_ == retainer_->SelfSize() 74 // is_root_node_ == retainer_->IsRootNode() 75 const MemoryRetainer* retainer_; 76 Node* wrapper_node_ = nullptr; 77 78 // Otherwise (retainer == nullptr), we set these fields in an ad-hoc way 79 bool is_root_node_ = false; 80 const char* name_; 81 size_t size_ = 0; 82 v8::EmbedderGraph::Node::Detachedness detachedness_ = 83 v8::EmbedderGraph::Node::Detachedness::kUnknown; 84 }; 85 86 void MemoryTracker::TrackFieldWithSize(const char* edge_name, 87 size_t size, 88 const char* node_name) { 89 if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name); 90 } 91 92 void MemoryTracker::TrackInlineFieldWithSize(const char* edge_name, 93 size_t size, 94 const char* node_name) { 95 if (size > 0) AddNode(GetNodeName(node_name, edge_name), size, edge_name); 96 CHECK(CurrentNode()); 97 CurrentNode()->size_ -= size; 98 } 99 100 void MemoryTracker::TrackField(const char* edge_name, 101 const MemoryRetainer& value, 102 const char* node_name) { 103 TrackField(edge_name, &value); 104 } 105 106 void MemoryTracker::TrackField(const char* edge_name, 107 const MemoryRetainer* value, 108 const char* node_name) { 109 if (value == nullptr) return; 110 auto it = seen_.find(value); 111 if (it != seen_.end()) { 112 graph_->AddEdge(CurrentNode(), it->second, edge_name); 113 } else { 114 Track(value, edge_name); 115 } 116 } 117 118 template <typename T, typename D> 119 void MemoryTracker::TrackField(const char* edge_name, 120 const std::unique_ptr<T, D>& value, 121 const char* node_name) { 122 if (value.get() == nullptr) { 123 return; 124 } 125 TrackField(edge_name, value.get(), node_name); 126 } 127 128 template <typename T> 129 void MemoryTracker::TrackField(const char* edge_name, 130 const std::shared_ptr<T>& value, 131 const char* node_name) { 132 if (value.get() == nullptr) { 133 return; 134 } 135 TrackField(edge_name, value.get(), node_name); 136 } 137 138 template <typename T, bool kIsWeak> 139 void MemoryTracker::TrackField(const char* edge_name, 140 const BaseObjectPtrImpl<T, kIsWeak>& value, 141 const char* node_name) { 142 if (value.get() == nullptr || kIsWeak) return; 143 TrackField(edge_name, value.get(), node_name); 144 } 145 146 template <typename T, typename Iterator> 147 void MemoryTracker::TrackField(const char* edge_name, 148 const T& value, 149 const char* node_name, 150 const char* element_name, 151 bool subtract_from_self) { 152 // If the container is empty, the size has been accounted into the parent's 153 // self size 154 if (value.begin() == value.end()) return; 155 // Fall back to edge name if node names are not provided 156 if (CurrentNode() != nullptr && subtract_from_self) { 157 // Shift the self size of this container out to a separate node 158 CurrentNode()->size_ -= sizeof(T); 159 } 160 PushNode(GetNodeName(node_name, edge_name), sizeof(T), edge_name); 161 for (Iterator it = value.begin(); it != value.end(); ++it) { 162 // Use nullptr as edge names so the elements appear as indexed properties 163 TrackField(nullptr, *it, element_name); 164 } 165 PopNode(); 166 } 167 168 template <typename T> 169 void MemoryTracker::TrackField(const char* edge_name, 170 const std::queue<T>& value, 171 const char* node_name, 172 const char* element_name) { 173 struct ContainerGetter : public std::queue<T> { 174 static const typename std::queue<T>::container_type& Get( 175 const std::queue<T>& value) { 176 return value.*&ContainerGetter::c; 177 } 178 }; 179 180 const auto& container = ContainerGetter::Get(value); 181 TrackField(edge_name, container, node_name, element_name); 182 } 183 184 template <typename T, typename test_for_number, typename dummy> 185 void MemoryTracker::TrackField(const char* edge_name, 186 const T& value, 187 const char* node_name) { 188 // For numbers, creating new nodes is not worth the overhead. 189 CurrentNode()->size_ += sizeof(T); 190 } 191 192 template <typename T, typename U> 193 void MemoryTracker::TrackField(const char* edge_name, 194 const std::pair<T, U>& value, 195 const char* node_name) { 196 PushNode(node_name == nullptr ? "pair" : node_name, 197 sizeof(const std::pair<T, U>), 198 edge_name); 199 // TODO(joyeecheung): special case if one of these is a number type 200 // that meets the test_for_number trait so that their sizes don't get 201 // merged into the pair node 202 TrackField("first", value.first); 203 TrackField("second", value.second); 204 PopNode(); 205 } 206 207 template <typename T> 208 void MemoryTracker::TrackField(const char* edge_name, 209 const std::basic_string<T>& value, 210 const char* node_name) { 211 TrackFieldWithSize(edge_name, value.size() * sizeof(T), "std::basic_string"); 212 } 213 214 template <typename T> 215 void MemoryTracker::TrackField(const char* edge_name, 216 const v8::Eternal<T>& value, 217 const char* node_name) { 218 TrackField(edge_name, value.Get(isolate_)); 219 } 220 221 template <typename T> 222 void MemoryTracker::TrackField(const char* edge_name, 223 const v8::PersistentBase<T>& value, 224 const char* node_name) { 225 if (value.IsWeak()) return; 226 TrackField(edge_name, value.Get(isolate_)); 227 } 228 229 template <typename T> 230 void MemoryTracker::TrackField(const char* edge_name, 231 const v8::Local<T>& value, 232 const char* node_name) { 233 if (!value.IsEmpty()) 234 graph_->AddEdge(CurrentNode(), 235 graph_->V8Node(value.template As<v8::Value>()), 236 edge_name); 237 } 238 239 template <typename T> 240 void MemoryTracker::TrackField(const char* edge_name, 241 const MallocedBuffer<T>& value, 242 const char* node_name) { 243 TrackFieldWithSize(edge_name, value.size, "MallocedBuffer"); 244 } 245 246 void MemoryTracker::TrackField(const char* edge_name, 247 const v8::BackingStore* value, 248 const char* node_name) { 249 TrackFieldWithSize(edge_name, value->ByteLength(), "BackingStore"); 250 } 251 252 void MemoryTracker::TrackField(const char* name, 253 const uv_buf_t& value, 254 const char* node_name) { 255 TrackFieldWithSize(name, value.len, "uv_buf_t"); 256 } 257 258 void MemoryTracker::TrackField(const char* name, 259 const uv_timer_t& value, 260 const char* node_name) { 261 TrackFieldWithSize(name, sizeof(value), "uv_timer_t"); 262 } 263 264 void MemoryTracker::TrackField(const char* name, 265 const uv_async_t& value, 266 const char* node_name) { 267 TrackFieldWithSize(name, sizeof(value), "uv_async_t"); 268 } 269 270 void MemoryTracker::TrackInlineField(const char* name, 271 const uv_async_t& value, 272 const char* node_name) { 273 TrackInlineFieldWithSize(name, sizeof(value), "uv_async_t"); 274 } 275 276 void MemoryTracker::Track(const MemoryRetainer* retainer, 277 const char* edge_name) { 278 v8::HandleScope handle_scope(isolate_); 279 auto it = seen_.find(retainer); 280 if (it != seen_.end()) { 281 if (CurrentNode() != nullptr) { 282 graph_->AddEdge(CurrentNode(), it->second, edge_name); 283 } 284 return; // It has already been tracked, no need to call MemoryInfo again 285 } 286 MemoryRetainerNode* n = PushNode(retainer, edge_name); 287 retainer->MemoryInfo(this); 288 CHECK_EQ(CurrentNode(), n); 289 CHECK_NE(n->size_, 0); 290 PopNode(); 291 } 292 293 void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer, 294 const char* edge_name) { 295 Track(retainer, edge_name); 296 CHECK(CurrentNode()); 297 CurrentNode()->size_ -= retainer->SelfSize(); 298 } 299 300 MemoryRetainerNode* MemoryTracker::CurrentNode() const { 301 if (node_stack_.empty()) return nullptr; 302 return node_stack_.top(); 303 } 304 305 MemoryRetainerNode* MemoryTracker::AddNode(const MemoryRetainer* retainer, 306 const char* edge_name) { 307 auto it = seen_.find(retainer); 308 if (it != seen_.end()) { 309 return it->second; 310 } 311 312 MemoryRetainerNode* n = new MemoryRetainerNode(this, retainer); 313 graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n)); 314 seen_[retainer] = n; 315 if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name); 316 317 if (n->JSWrapperNode() != nullptr) { 318 graph_->AddEdge(n, n->JSWrapperNode(), "native_to_javascript"); 319 graph_->AddEdge(n->JSWrapperNode(), n, "javascript_to_native"); 320 } 321 322 return n; 323 } 324 325 MemoryRetainerNode* MemoryTracker::AddNode(const char* node_name, 326 size_t size, 327 const char* edge_name) { 328 MemoryRetainerNode* n = new MemoryRetainerNode(this, node_name, size); 329 graph_->AddNode(std::unique_ptr<v8::EmbedderGraph::Node>(n)); 330 331 if (CurrentNode() != nullptr) graph_->AddEdge(CurrentNode(), n, edge_name); 332 333 return n; 334 } 335 336 MemoryRetainerNode* MemoryTracker::PushNode(const MemoryRetainer* retainer, 337 const char* edge_name) { 338 MemoryRetainerNode* n = AddNode(retainer, edge_name); 339 node_stack_.push(n); 340 return n; 341 } 342 343 MemoryRetainerNode* MemoryTracker::PushNode(const char* node_name, 344 size_t size, 345 const char* edge_name) { 346 MemoryRetainerNode* n = AddNode(node_name, size, edge_name); 347 node_stack_.push(n); 348 return n; 349 } 350 351 void MemoryTracker::PopNode() { 352 node_stack_.pop(); 353 } 354 355 } // namespace node 356 357 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 358 359 #endif // SRC_MEMORY_TRACKER_INL_H_