1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_V8_PROFILER_H_ 6 #define V8_V8_PROFILER_H_ 7 8 #include <limits.h> 9 10 #include <memory> 11 #include <unordered_set> 12 #include <vector> 13 14 #include "v8-local-handle.h" // NOLINT(build/include_directory) 15 #include "v8-message.h" // NOLINT(build/include_directory) 16 #include "v8-persistent-handle.h" // NOLINT(build/include_directory) 17 18 /** 19 * Profiler support for the V8 JavaScript engine. 20 */ 21 namespace v8 { 22 23 enum class EmbedderStateTag : uint8_t; 24 class HeapGraphNode; 25 struct HeapStatsUpdate; 26 class Object; 27 enum StateTag : int; 28 29 using NativeObject = void*; 30 using SnapshotObjectId = uint32_t; 31 using ProfilerId = uint32_t; 32 33 struct CpuProfileDeoptFrame { 34 int script_id; 35 size_t position; 36 }; 37 38 namespace internal { 39 class CpuProfile; 40 } // namespace internal 41 42 } // namespace v8 43 44 #ifdef V8_OS_WIN 45 template class V8_EXPORT std::vector<v8::CpuProfileDeoptFrame>; 46 #endif 47 48 namespace v8 { 49 50 struct V8_EXPORT CpuProfileDeoptInfo { 51 /** A pointer to a static string owned by v8. */ 52 const char* deopt_reason; 53 std::vector<CpuProfileDeoptFrame> stack; 54 }; 55 56 } // namespace v8 57 58 #ifdef V8_OS_WIN 59 template class V8_EXPORT std::vector<v8::CpuProfileDeoptInfo>; 60 #endif 61 62 namespace v8 { 63 64 /** 65 * CpuProfileNode represents a node in a call graph. 66 */ 67 class V8_EXPORT CpuProfileNode { 68 public: 69 struct LineTick { 70 /** The 1-based number of the source line where the function originates. */ 71 int line; 72 73 /** The count of samples associated with the source line. */ 74 unsigned int hit_count; 75 }; 76 77 // An annotation hinting at the source of a CpuProfileNode. 78 enum SourceType { 79 // User-supplied script with associated resource information. 80 kScript = 0, 81 // Native scripts and provided builtins. 82 kBuiltin = 1, 83 // Callbacks into native code. 84 kCallback = 2, 85 // VM-internal functions or state. 86 kInternal = 3, 87 // A node that failed to symbolize. 88 kUnresolved = 4, 89 }; 90 91 /** Returns function name (empty string for anonymous functions.) */ 92 Local<String> GetFunctionName() const; 93 94 /** 95 * Returns function name (empty string for anonymous functions.) 96 * The string ownership is *not* passed to the caller. It stays valid until 97 * profile is deleted. The function is thread safe. 98 */ 99 const char* GetFunctionNameStr() const; 100 101 /** Returns id of the script where function is located. */ 102 int GetScriptId() const; 103 104 /** Returns resource name for script from where the function originates. */ 105 Local<String> GetScriptResourceName() const; 106 107 /** 108 * Returns resource name for script from where the function originates. 109 * The string ownership is *not* passed to the caller. It stays valid until 110 * profile is deleted. The function is thread safe. 111 */ 112 const char* GetScriptResourceNameStr() const; 113 114 /** 115 * Return true if the script from where the function originates is flagged as 116 * being shared cross-origin. 117 */ 118 bool IsScriptSharedCrossOrigin() const; 119 120 /** 121 * Returns the number, 1-based, of the line where the function originates. 122 * kNoLineNumberInfo if no line number information is available. 123 */ 124 int GetLineNumber() const; 125 126 /** 127 * Returns 1-based number of the column where the function originates. 128 * kNoColumnNumberInfo if no column number information is available. 129 */ 130 int GetColumnNumber() const; 131 132 /** 133 * Returns the number of the function's source lines that collect the samples. 134 */ 135 unsigned int GetHitLineCount() const; 136 137 /** Returns the set of source lines that collect the samples. 138 * The caller allocates buffer and responsible for releasing it. 139 * True if all available entries are copied, otherwise false. 140 * The function copies nothing if buffer is not large enough. 141 */ 142 bool GetLineTicks(LineTick* entries, unsigned int length) const; 143 144 /** Returns bailout reason for the function 145 * if the optimization was disabled for it. 146 */ 147 const char* GetBailoutReason() const; 148 149 /** 150 * Returns the count of samples where the function was currently executing. 151 */ 152 unsigned GetHitCount() const; 153 154 /** Returns id of the node. The id is unique within the tree */ 155 unsigned GetNodeId() const; 156 157 /** 158 * Gets the type of the source which the node was captured from. 159 */ 160 SourceType GetSourceType() const; 161 162 /** Returns child nodes count of the node. */ 163 int GetChildrenCount() const; 164 165 /** Retrieves a child node by index. */ 166 const CpuProfileNode* GetChild(int index) const; 167 168 /** Retrieves the ancestor node, or null if the root. */ 169 const CpuProfileNode* GetParent() const; 170 171 /** Retrieves deopt infos for the node. */ 172 const std::vector<CpuProfileDeoptInfo>& GetDeoptInfos() const; 173 174 static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; 175 static const int kNoColumnNumberInfo = Message::kNoColumnInfo; 176 }; 177 178 /** 179 * An interface for exporting data from V8, using "push" model. 180 */ 181 class V8_EXPORT OutputStream { 182 public: 183 enum WriteResult { 184 kContinue = 0, 185 kAbort = 1 186 }; 187 virtual ~OutputStream() = default; 188 /** Notify about the end of stream. */ 189 virtual void EndOfStream() = 0; 190 /** Get preferred output chunk size. Called only once. */ GetChunkSize()191 virtual int GetChunkSize() { return 1024; } 192 /** 193 * Writes the next chunk of snapshot data into the stream. Writing 194 * can be stopped by returning kAbort as function result. EndOfStream 195 * will not be called in case writing was aborted. 196 */ 197 virtual WriteResult WriteAsciiChunk(char* data, int size) = 0; 198 /** 199 * Writes the next chunk of heap stats data into the stream. Writing 200 * can be stopped by returning kAbort as function result. EndOfStream 201 * will not be called in case writing was aborted. 202 */ WriteHeapStatsChunk(HeapStatsUpdate * data,int count)203 virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) { 204 return kAbort; 205 } 206 }; 207 208 /** 209 * CpuProfile contains a CPU profile in a form of top-down call tree 210 * (from main() down to functions that do all the work). 211 */ 212 class V8_EXPORT CpuProfile { 213 public: 214 enum SerializationFormat { 215 kJSON = 0 // See format description near 'Serialize' method. 216 }; 217 /** Returns CPU profile title. */ 218 Local<String> GetTitle() const; 219 220 /** Returns the root node of the top down call tree. */ 221 const CpuProfileNode* GetTopDownRoot() const; 222 223 /** 224 * Returns number of samples recorded. The samples are not recorded unless 225 * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true. 226 */ 227 int GetSamplesCount() const; 228 229 /** 230 * Returns profile node corresponding to the top frame the sample at 231 * the given index. 232 */ 233 const CpuProfileNode* GetSample(int index) const; 234 235 /** 236 * Returns the timestamp of the sample. The timestamp is the number of 237 * microseconds since some unspecified starting point. 238 * The point is equal to the starting point used by GetStartTime. 239 */ 240 int64_t GetSampleTimestamp(int index) const; 241 242 /** 243 * Returns time when the profile recording was started (in microseconds) 244 * since some unspecified starting point. 245 */ 246 int64_t GetStartTime() const; 247 248 /** 249 * Returns state of the vm when sample was captured. 250 */ 251 StateTag GetSampleState(int index) const; 252 253 /** 254 * Returns state of the embedder when sample was captured. 255 */ 256 EmbedderStateTag GetSampleEmbedderState(int index) const; 257 258 /** 259 * Returns time when the profile recording was stopped (in microseconds) 260 * since some unspecified starting point. 261 * The point is equal to the starting point used by GetStartTime. 262 */ 263 int64_t GetEndTime() const; 264 265 /** 266 * Deletes the profile and removes it from CpuProfiler's list. 267 * All pointers to nodes previously returned become invalid. 268 */ 269 void Delete(); 270 271 /** 272 * Prepare a serialized representation of the profile. The result 273 * is written into the stream provided in chunks of specified size. 274 * 275 * For the JSON format, heap contents are represented as an object 276 * with the following structure: 277 * 278 * { 279 * nodes: [nodes array], 280 * startTime: number, 281 * endTime: number 282 * samples: [strings array] 283 * timeDeltas: [numbers array] 284 * } 285 * 286 */ 287 void Serialize(OutputStream* stream, 288 SerializationFormat format = kJSON) const; 289 }; 290 291 enum CpuProfilingMode { 292 // In the resulting CpuProfile tree, intermediate nodes in a stack trace 293 // (from the root to a leaf) will have line numbers that point to the start 294 // line of the function, rather than the line of the callsite of the child. 295 kLeafNodeLineNumbers, 296 // In the resulting CpuProfile tree, nodes are separated based on the line 297 // number of their callsite in their parent. 298 kCallerLineNumbers, 299 }; 300 301 // Determines how names are derived for functions sampled. 302 enum CpuProfilingNamingMode { 303 // Use the immediate name of functions at compilation time. 304 kStandardNaming, 305 // Use more verbose naming for functions without names, inferred from scope 306 // where possible. 307 kDebugNaming, 308 }; 309 310 enum CpuProfilingLoggingMode { 311 // Enables logging when a profile is active, and disables logging when all 312 // profiles are detached. 313 kLazyLogging, 314 // Enables logging for the lifetime of the CpuProfiler. Calls to 315 // StartRecording are faster, at the expense of runtime overhead. 316 kEagerLogging, 317 }; 318 319 // Enum for returning profiling status. Once StartProfiling is called, 320 // we want to return to clients whether the profiling was able to start 321 // correctly, or return a descriptive error. 322 enum class CpuProfilingStatus { 323 kStarted, 324 kAlreadyStarted, 325 kErrorTooManyProfilers 326 }; 327 328 /** 329 * Result from StartProfiling returning the Profiling Status, and 330 * id of the started profiler, or 0 if profiler is not started 331 */ 332 struct CpuProfilingResult { 333 const ProfilerId id; 334 const CpuProfilingStatus status; 335 }; 336 337 /** 338 * Delegate for when max samples reached and samples are discarded. 339 */ 340 class V8_EXPORT DiscardedSamplesDelegate { 341 public: 342 DiscardedSamplesDelegate() = default; 343 344 virtual ~DiscardedSamplesDelegate() = default; 345 virtual void Notify() = 0; 346 GetId()347 ProfilerId GetId() const { return profiler_id_; } 348 349 private: 350 friend internal::CpuProfile; 351 SetId(ProfilerId id)352 void SetId(ProfilerId id) { profiler_id_ = id; } 353 354 ProfilerId profiler_id_; 355 }; 356 357 /** 358 * Optional profiling attributes. 359 */ 360 class V8_EXPORT CpuProfilingOptions { 361 public: 362 // Indicates that the sample buffer size should not be explicitly limited. 363 static const unsigned kNoSampleLimit = UINT_MAX; 364 365 /** 366 * \param mode Type of computation of stack frame line numbers. 367 * \param max_samples The maximum number of samples that should be recorded by 368 * the profiler. Samples obtained after this limit will be 369 * discarded. 370 * \param sampling_interval_us controls the profile-specific target 371 * sampling interval. The provided sampling 372 * interval will be snapped to the next lowest 373 * non-zero multiple of the profiler's sampling 374 * interval, set via SetSamplingInterval(). If 375 * zero, the sampling interval will be equal to 376 * the profiler's sampling interval. 377 * \param filter_context If specified, profiles will only contain frames 378 * using this context. Other frames will be elided. 379 */ 380 CpuProfilingOptions( 381 CpuProfilingMode mode = kLeafNodeLineNumbers, 382 unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0, 383 MaybeLocal<Context> filter_context = MaybeLocal<Context>()); 384 mode()385 CpuProfilingMode mode() const { return mode_; } max_samples()386 unsigned max_samples() const { return max_samples_; } sampling_interval_us()387 int sampling_interval_us() const { return sampling_interval_us_; } 388 389 private: 390 friend class internal::CpuProfile; 391 has_filter_context()392 bool has_filter_context() const { return !filter_context_.IsEmpty(); } 393 void* raw_filter_context() const; 394 395 CpuProfilingMode mode_; 396 unsigned max_samples_; 397 int sampling_interval_us_; 398 CopyablePersistentTraits<Context>::CopyablePersistent filter_context_; 399 }; 400 401 /** 402 * Interface for controlling CPU profiling. Instance of the 403 * profiler can be created using v8::CpuProfiler::New method. 404 */ 405 class V8_EXPORT CpuProfiler { 406 public: 407 /** 408 * Creates a new CPU profiler for the |isolate|. The isolate must be 409 * initialized. The profiler object must be disposed after use by calling 410 * |Dispose| method. 411 */ 412 static CpuProfiler* New(Isolate* isolate, 413 CpuProfilingNamingMode = kDebugNaming, 414 CpuProfilingLoggingMode = kLazyLogging); 415 416 /** 417 * Synchronously collect current stack sample in all profilers attached to 418 * the |isolate|. The call does not affect number of ticks recorded for 419 * the current top node. 420 */ 421 static void CollectSample(Isolate* isolate); 422 423 /** 424 * Disposes the CPU profiler object. 425 */ 426 void Dispose(); 427 428 /** 429 * Changes default CPU profiler sampling interval to the specified number 430 * of microseconds. Default interval is 1000us. This method must be called 431 * when there are no profiles being recorded. 432 */ 433 void SetSamplingInterval(int us); 434 435 /** 436 * Sets whether or not the profiler should prioritize consistency of sample 437 * periodicity on Windows. Disabling this can greatly reduce CPU usage, but 438 * may result in greater variance in sample timings from the platform's 439 * scheduler. Defaults to enabled. This method must be called when there are 440 * no profiles being recorded. 441 */ 442 void SetUsePreciseSampling(bool); 443 444 /** 445 * Starts collecting a CPU profile. Several profiles may be collected at once. 446 * Generates an anonymous profiler, without a String identifier. 447 */ 448 CpuProfilingResult Start( 449 CpuProfilingOptions options, 450 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr); 451 452 /** 453 * Starts collecting a CPU profile. Title may be an empty string. Several 454 * profiles may be collected at once. Attempts to start collecting several 455 * profiles with the same title are silently ignored. 456 */ 457 CpuProfilingResult Start( 458 Local<String> title, CpuProfilingOptions options, 459 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr); 460 461 /** 462 * Starts profiling with the same semantics as above, except with expanded 463 * parameters. 464 * 465 * |record_samples| parameter controls whether individual samples should 466 * be recorded in addition to the aggregated tree. 467 * 468 * |max_samples| controls the maximum number of samples that should be 469 * recorded by the profiler. Samples obtained after this limit will be 470 * discarded. 471 */ 472 CpuProfilingResult Start( 473 Local<String> title, CpuProfilingMode mode, bool record_samples = false, 474 unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); 475 476 /** 477 * The same as StartProfiling above, but the CpuProfilingMode defaults to 478 * kLeafNodeLineNumbers mode, which was the previous default behavior of the 479 * profiler. 480 */ 481 CpuProfilingResult Start(Local<String> title, bool record_samples = false); 482 483 /** 484 * Starts collecting a CPU profile. Title may be an empty string. Several 485 * profiles may be collected at once. Attempts to start collecting several 486 * profiles with the same title are silently ignored. 487 */ 488 CpuProfilingStatus StartProfiling( 489 Local<String> title, CpuProfilingOptions options, 490 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr); 491 492 /** 493 * Starts profiling with the same semantics as above, except with expanded 494 * parameters. 495 * 496 * |record_samples| parameter controls whether individual samples should 497 * be recorded in addition to the aggregated tree. 498 * 499 * |max_samples| controls the maximum number of samples that should be 500 * recorded by the profiler. Samples obtained after this limit will be 501 * discarded. 502 */ 503 CpuProfilingStatus StartProfiling( 504 Local<String> title, CpuProfilingMode mode, bool record_samples = false, 505 unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); 506 507 /** 508 * The same as StartProfiling above, but the CpuProfilingMode defaults to 509 * kLeafNodeLineNumbers mode, which was the previous default behavior of the 510 * profiler. 511 */ 512 CpuProfilingStatus StartProfiling(Local<String> title, 513 bool record_samples = false); 514 515 /** 516 * Stops collecting CPU profile with a given id and returns it. 517 */ 518 CpuProfile* Stop(ProfilerId id); 519 520 /** 521 * Stops collecting CPU profile with a given title and returns it. 522 * If the title given is empty, finishes the last profile started. 523 */ 524 CpuProfile* StopProfiling(Local<String> title); 525 526 /** 527 * Generate more detailed source positions to code objects. This results in 528 * better results when mapping profiling samples to script source. 529 */ 530 static void UseDetailedSourcePositionsForProfiling(Isolate* isolate); 531 532 private: 533 CpuProfiler(); 534 ~CpuProfiler(); 535 CpuProfiler(const CpuProfiler&); 536 CpuProfiler& operator=(const CpuProfiler&); 537 }; 538 539 /** 540 * HeapSnapshotEdge represents a directed connection between heap 541 * graph nodes: from retainers to retained nodes. 542 */ 543 class V8_EXPORT HeapGraphEdge { 544 public: 545 enum Type { 546 kContextVariable = 0, // A variable from a function context. 547 kElement = 1, // An element of an array. 548 kProperty = 2, // A named object property. 549 kInternal = 3, // A link that can't be accessed from JS, 550 // thus, its name isn't a real property name 551 // (e.g. parts of a ConsString). 552 kHidden = 4, // A link that is needed for proper sizes 553 // calculation, but may be hidden from user. 554 kShortcut = 5, // A link that must not be followed during 555 // sizes calculation. 556 kWeak = 6 // A weak reference (ignored by the GC). 557 }; 558 559 /** Returns edge type (see HeapGraphEdge::Type). */ 560 Type GetType() const; 561 562 /** 563 * Returns edge name. This can be a variable name, an element index, or 564 * a property name. 565 */ 566 Local<Value> GetName() const; 567 568 /** Returns origin node. */ 569 const HeapGraphNode* GetFromNode() const; 570 571 /** Returns destination node. */ 572 const HeapGraphNode* GetToNode() const; 573 }; 574 575 576 /** 577 * HeapGraphNode represents a node in a heap graph. 578 */ 579 class V8_EXPORT HeapGraphNode { 580 public: 581 enum Type { 582 kHidden = 0, // Hidden node, may be filtered when shown to user. 583 kArray = 1, // An array of elements. 584 kString = 2, // A string. 585 kObject = 3, // A JS object (except for arrays and strings). 586 kCode = 4, // Compiled code. 587 kClosure = 5, // Function closure. 588 kRegExp = 6, // RegExp. 589 kHeapNumber = 7, // Number stored in the heap. 590 kNative = 8, // Native object (not from V8 heap). 591 kSynthetic = 9, // Synthetic object, usually used for grouping 592 // snapshot items together. 593 kConsString = 10, // Concatenated string. A pair of pointers to strings. 594 kSlicedString = 11, // Sliced string. A fragment of another string. 595 kSymbol = 12, // A Symbol (ES6). 596 kBigInt = 13 // BigInt. 597 }; 598 599 /** Returns node type (see HeapGraphNode::Type). */ 600 Type GetType() const; 601 602 /** 603 * Returns node name. Depending on node's type this can be the name 604 * of the constructor (for objects), the name of the function (for 605 * closures), string value, or an empty string (for compiled code). 606 */ 607 Local<String> GetName() const; 608 609 /** 610 * Returns node id. For the same heap object, the id remains the same 611 * across all snapshots. 612 */ 613 SnapshotObjectId GetId() const; 614 615 /** Returns node's own size, in bytes. */ 616 size_t GetShallowSize() const; 617 618 /** Returns child nodes count of the node. */ 619 int GetChildrenCount() const; 620 621 /** Retrieves a child by index. */ 622 const HeapGraphEdge* GetChild(int index) const; 623 }; 624 625 /** 626 * HeapSnapshots record the state of the JS heap at some moment. 627 */ 628 class V8_EXPORT HeapSnapshot { 629 public: 630 enum SerializationFormat { 631 kJSON = 0 // See format description near 'Serialize' method. 632 }; 633 634 /** Returns the root node of the heap graph. */ 635 const HeapGraphNode* GetRoot() const; 636 637 /** Returns a node by its id. */ 638 const HeapGraphNode* GetNodeById(SnapshotObjectId id) const; 639 640 /** Returns total nodes count in the snapshot. */ 641 int GetNodesCount() const; 642 643 /** Returns a node by index. */ 644 const HeapGraphNode* GetNode(int index) const; 645 646 /** Returns a max seen JS object Id. */ 647 SnapshotObjectId GetMaxSnapshotJSObjectId() const; 648 649 /** 650 * Deletes the snapshot and removes it from HeapProfiler's list. 651 * All pointers to nodes, edges and paths previously returned become 652 * invalid. 653 */ 654 void Delete(); 655 656 /** 657 * Prepare a serialized representation of the snapshot. The result 658 * is written into the stream provided in chunks of specified size. 659 * The total length of the serialized snapshot is unknown in 660 * advance, it can be roughly equal to JS heap size (that means, 661 * it can be really big - tens of megabytes). 662 * 663 * For the JSON format, heap contents are represented as an object 664 * with the following structure: 665 * 666 * { 667 * snapshot: { 668 * title: "...", 669 * uid: nnn, 670 * meta: { meta-info }, 671 * node_count: nnn, 672 * edge_count: nnn 673 * }, 674 * nodes: [nodes array], 675 * edges: [edges array], 676 * strings: [strings array] 677 * } 678 * 679 * Nodes reference strings, other nodes, and edges by their indexes 680 * in corresponding arrays. 681 */ 682 void Serialize(OutputStream* stream, 683 SerializationFormat format = kJSON) const; 684 }; 685 686 687 /** 688 * An interface for reporting progress and controlling long-running 689 * activities. 690 */ 691 class V8_EXPORT ActivityControl { 692 public: 693 enum ControlOption { 694 kContinue = 0, 695 kAbort = 1 696 }; 697 virtual ~ActivityControl() = default; 698 /** 699 * Notify about current progress. The activity can be stopped by 700 * returning kAbort as the callback result. 701 */ 702 virtual ControlOption ReportProgressValue(uint32_t done, uint32_t total) = 0; 703 }; 704 705 /** 706 * AllocationProfile is a sampled profile of allocations done by the program. 707 * This is structured as a call-graph. 708 */ 709 class V8_EXPORT AllocationProfile { 710 public: 711 struct Allocation { 712 /** 713 * Size of the sampled allocation object. 714 */ 715 size_t size; 716 717 /** 718 * The number of objects of such size that were sampled. 719 */ 720 unsigned int count; 721 }; 722 723 /** 724 * Represents a node in the call-graph. 725 */ 726 struct Node { 727 /** 728 * Name of the function. May be empty for anonymous functions or if the 729 * script corresponding to this function has been unloaded. 730 */ 731 Local<String> name; 732 733 /** 734 * Name of the script containing the function. May be empty if the script 735 * name is not available, or if the script has been unloaded. 736 */ 737 Local<String> script_name; 738 739 /** 740 * id of the script where the function is located. May be equal to 741 * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist. 742 */ 743 int script_id; 744 745 /** 746 * Start position of the function in the script. 747 */ 748 int start_position; 749 750 /** 751 * 1-indexed line number where the function starts. May be 752 * kNoLineNumberInfo if no line number information is available. 753 */ 754 int line_number; 755 756 /** 757 * 1-indexed column number where the function starts. May be 758 * kNoColumnNumberInfo if no line number information is available. 759 */ 760 int column_number; 761 762 /** 763 * Unique id of the node. 764 */ 765 uint32_t node_id; 766 767 /** 768 * List of callees called from this node for which we have sampled 769 * allocations. The lifetime of the children is scoped to the containing 770 * AllocationProfile. 771 */ 772 std::vector<Node*> children; 773 774 /** 775 * List of self allocations done by this node in the call-graph. 776 */ 777 std::vector<Allocation> allocations; 778 }; 779 780 /** 781 * Represent a single sample recorded for an allocation. 782 */ 783 struct Sample { 784 /** 785 * id of the node in the profile tree. 786 */ 787 uint32_t node_id; 788 789 /** 790 * Size of the sampled allocation object. 791 */ 792 size_t size; 793 794 /** 795 * The number of objects of such size that were sampled. 796 */ 797 unsigned int count; 798 799 /** 800 * Unique time-ordered id of the allocation sample. Can be used to track 801 * what samples were added or removed between two snapshots. 802 */ 803 uint64_t sample_id; 804 }; 805 806 /** 807 * Returns the root node of the call-graph. The root node corresponds to an 808 * empty JS call-stack. The lifetime of the returned Node* is scoped to the 809 * containing AllocationProfile. 810 */ 811 virtual Node* GetRootNode() = 0; 812 virtual const std::vector<Sample>& GetSamples() = 0; 813 814 virtual ~AllocationProfile() = default; 815 816 static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; 817 static const int kNoColumnNumberInfo = Message::kNoColumnInfo; 818 }; 819 820 /** 821 * An object graph consisting of embedder objects and V8 objects. 822 * Edges of the graph are strong references between the objects. 823 * The embedder can build this graph during heap snapshot generation 824 * to include the embedder objects in the heap snapshot. 825 * Usage: 826 * 1) Define derived class of EmbedderGraph::Node for embedder objects. 827 * 2) Set the build embedder graph callback on the heap profiler using 828 * HeapProfiler::AddBuildEmbedderGraphCallback. 829 * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from 830 * node1 to node2. 831 * 4) To represent references from/to V8 object, construct V8 nodes using 832 * graph->V8Node(value). 833 */ 834 class V8_EXPORT EmbedderGraph { 835 public: 836 class Node { 837 public: 838 /** 839 * Detachedness specifies whether an object is attached or detached from the 840 * main application state. While unkown in general, there may be objects 841 * that specifically know their state. V8 passes this information along in 842 * the snapshot. Users of the snapshot may use it to annotate the object 843 * graph. 844 */ 845 enum class Detachedness : uint8_t { 846 kUnknown = 0, 847 kAttached = 1, 848 kDetached = 2, 849 }; 850 851 Node() = default; 852 virtual ~Node() = default; 853 virtual const char* Name() = 0; 854 virtual size_t SizeInBytes() = 0; 855 /** 856 * The corresponding V8 wrapper node if not null. 857 * During heap snapshot generation the embedder node and the V8 wrapper 858 * node will be merged into one node to simplify retaining paths. 859 */ WrapperNode()860 virtual Node* WrapperNode() { return nullptr; } IsRootNode()861 virtual bool IsRootNode() { return false; } 862 /** Must return true for non-V8 nodes. */ IsEmbedderNode()863 virtual bool IsEmbedderNode() { return true; } 864 /** 865 * Optional name prefix. It is used in Chrome for tagging detached nodes. 866 */ NamePrefix()867 virtual const char* NamePrefix() { return nullptr; } 868 869 /** 870 * Returns the NativeObject that can be used for querying the 871 * |HeapSnapshot|. 872 */ GetNativeObject()873 virtual NativeObject GetNativeObject() { return nullptr; } 874 875 /** 876 * Detachedness state of a given object. While unkown in general, there may 877 * be objects that specifically know their state. V8 passes this information 878 * along in the snapshot. Users of the snapshot may use it to annotate the 879 * object graph. 880 */ GetDetachedness()881 virtual Detachedness GetDetachedness() { return Detachedness::kUnknown; } 882 883 Node(const Node&) = delete; 884 Node& operator=(const Node&) = delete; 885 }; 886 887 /** 888 * Returns a node corresponding to the given V8 value. Ownership is not 889 * transferred. The result pointer is valid while the graph is alive. 890 */ 891 virtual Node* V8Node(const v8::Local<v8::Value>& value) = 0; 892 893 /** 894 * Adds the given node to the graph and takes ownership of the node. 895 * Returns a raw pointer to the node that is valid while the graph is alive. 896 */ 897 virtual Node* AddNode(std::unique_ptr<Node> node) = 0; 898 899 /** 900 * Adds an edge that represents a strong reference from the given 901 * node |from| to the given node |to|. The nodes must be added to the graph 902 * before calling this function. 903 * 904 * If name is nullptr, the edge will have auto-increment indexes, otherwise 905 * it will be named accordingly. 906 */ 907 virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0; 908 909 virtual ~EmbedderGraph() = default; 910 }; 911 912 /** 913 * Interface for controlling heap profiling. Instance of the 914 * profiler can be retrieved using v8::Isolate::GetHeapProfiler. 915 */ 916 class V8_EXPORT HeapProfiler { 917 public: 918 enum SamplingFlags { 919 kSamplingNoFlags = 0, 920 kSamplingForceGC = 1 << 0, 921 }; 922 923 /** 924 * Callback function invoked during heap snapshot generation to retrieve 925 * the embedder object graph. The callback should use graph->AddEdge(..) to 926 * add references between the objects. 927 * The callback must not trigger garbage collection in V8. 928 */ 929 typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate, 930 v8::EmbedderGraph* graph, 931 void* data); 932 933 /** 934 * Callback function invoked during heap snapshot generation to retrieve 935 * the detachedness state of an object referenced by a TracedReference. 936 * 937 * The callback takes Local<Value> as parameter to allow the embedder to 938 * unpack the TracedReference into a Local and reuse that Local for different 939 * purposes. 940 */ 941 using GetDetachednessCallback = EmbedderGraph::Node::Detachedness (*)( 942 v8::Isolate* isolate, const v8::Local<v8::Value>& v8_value, 943 uint16_t class_id, void* data); 944 945 /** Returns the number of snapshots taken. */ 946 int GetSnapshotCount(); 947 948 /** Returns a snapshot by index. */ 949 const HeapSnapshot* GetHeapSnapshot(int index); 950 951 /** 952 * Returns SnapshotObjectId for a heap object referenced by |value| if 953 * it has been seen by the heap profiler, kUnknownObjectId otherwise. 954 */ 955 SnapshotObjectId GetObjectId(Local<Value> value); 956 957 /** 958 * Returns SnapshotObjectId for a native object referenced by |value| if it 959 * has been seen by the heap profiler, kUnknownObjectId otherwise. 960 */ 961 SnapshotObjectId GetObjectId(NativeObject value); 962 963 /** 964 * Returns heap object with given SnapshotObjectId if the object is alive, 965 * otherwise empty handle is returned. 966 */ 967 Local<Value> FindObjectById(SnapshotObjectId id); 968 969 /** 970 * Clears internal map from SnapshotObjectId to heap object. The new objects 971 * will not be added into it unless a heap snapshot is taken or heap object 972 * tracking is kicked off. 973 */ 974 void ClearObjectIds(); 975 976 /** 977 * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return 978 * it in case heap profiler cannot find id for the object passed as 979 * parameter. HeapSnapshot::GetNodeById will always return NULL for such id. 980 */ 981 static const SnapshotObjectId kUnknownObjectId = 0; 982 983 /** 984 * Callback interface for retrieving user friendly names of global objects. 985 */ 986 class ObjectNameResolver { 987 public: 988 /** 989 * Returns name to be used in the heap snapshot for given node. Returned 990 * string must stay alive until snapshot collection is completed. 991 */ 992 virtual const char* GetName(Local<Object> object) = 0; 993 994 protected: 995 virtual ~ObjectNameResolver() = default; 996 }; 997 998 /** 999 * Takes a heap snapshot and returns it. 1000 */ 1001 const HeapSnapshot* TakeHeapSnapshot( 1002 ActivityControl* control = nullptr, 1003 ObjectNameResolver* global_object_name_resolver = nullptr, 1004 bool treat_global_objects_as_roots = true, 1005 bool capture_numeric_value = false); 1006 1007 /** 1008 * Starts tracking of heap objects population statistics. After calling 1009 * this method, all heap objects relocations done by the garbage collector 1010 * are being registered. 1011 * 1012 * |track_allocations| parameter controls whether stack trace of each 1013 * allocation in the heap will be recorded and reported as part of 1014 * HeapSnapshot. 1015 */ 1016 void StartTrackingHeapObjects(bool track_allocations = false); 1017 1018 /** 1019 * Adds a new time interval entry to the aggregated statistics array. The 1020 * time interval entry contains information on the current heap objects 1021 * population size. The method also updates aggregated statistics and 1022 * reports updates for all previous time intervals via the OutputStream 1023 * object. Updates on each time interval are provided as a stream of the 1024 * HeapStatsUpdate structure instances. 1025 * If |timestamp_us| is supplied, timestamp of the new entry will be written 1026 * into it. The return value of the function is the last seen heap object Id. 1027 * 1028 * StartTrackingHeapObjects must be called before the first call to this 1029 * method. 1030 */ 1031 SnapshotObjectId GetHeapStats(OutputStream* stream, 1032 int64_t* timestamp_us = nullptr); 1033 1034 /** 1035 * Stops tracking of heap objects population statistics, cleans up all 1036 * collected data. StartHeapObjectsTracking must be called again prior to 1037 * calling GetHeapStats next time. 1038 */ 1039 void StopTrackingHeapObjects(); 1040 1041 /** 1042 * Starts gathering a sampling heap profile. A sampling heap profile is 1043 * similar to tcmalloc's heap profiler and Go's mprof. It samples object 1044 * allocations and builds an online 'sampling' heap profile. At any point in 1045 * time, this profile is expected to be a representative sample of objects 1046 * currently live in the system. Each sampled allocation includes the stack 1047 * trace at the time of allocation, which makes this really useful for memory 1048 * leak detection. 1049 * 1050 * This mechanism is intended to be cheap enough that it can be used in 1051 * production with minimal performance overhead. 1052 * 1053 * Allocations are sampled using a randomized Poisson process. On average, one 1054 * allocation will be sampled every |sample_interval| bytes allocated. The 1055 * |stack_depth| parameter controls the maximum number of stack frames to be 1056 * captured on each allocation. 1057 * 1058 * NOTE: This is a proof-of-concept at this point. Right now we only sample 1059 * newspace allocations. Support for paged space allocation (e.g. pre-tenured 1060 * objects, large objects, code objects, etc.) and native allocations 1061 * doesn't exist yet, but is anticipated in the future. 1062 * 1063 * Objects allocated before the sampling is started will not be included in 1064 * the profile. 1065 * 1066 * Returns false if a sampling heap profiler is already running. 1067 */ 1068 bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024, 1069 int stack_depth = 16, 1070 SamplingFlags flags = kSamplingNoFlags); 1071 1072 /** 1073 * Stops the sampling heap profile and discards the current profile. 1074 */ 1075 void StopSamplingHeapProfiler(); 1076 1077 /** 1078 * Returns the sampled profile of allocations allocated (and still live) since 1079 * StartSamplingHeapProfiler was called. The ownership of the pointer is 1080 * transferred to the caller. Returns nullptr if sampling heap profiler is not 1081 * active. 1082 */ 1083 AllocationProfile* GetAllocationProfile(); 1084 1085 /** 1086 * Deletes all snapshots taken. All previously returned pointers to 1087 * snapshots and their contents become invalid after this call. 1088 */ 1089 void DeleteAllHeapSnapshots(); 1090 1091 void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, 1092 void* data); 1093 void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, 1094 void* data); 1095 1096 void SetGetDetachednessCallback(GetDetachednessCallback callback, void* data); 1097 1098 /** 1099 * Default value of persistent handle class ID. Must not be used to 1100 * define a class. Can be used to reset a class of a persistent 1101 * handle. 1102 */ 1103 static const uint16_t kPersistentHandleNoClassId = 0; 1104 1105 private: 1106 HeapProfiler(); 1107 ~HeapProfiler(); 1108 HeapProfiler(const HeapProfiler&); 1109 HeapProfiler& operator=(const HeapProfiler&); 1110 }; 1111 1112 /** 1113 * A struct for exporting HeapStats data from V8, using "push" model. 1114 * See HeapProfiler::GetHeapStats. 1115 */ 1116 struct HeapStatsUpdate { HeapStatsUpdateHeapStatsUpdate1117 HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size) 1118 : index(index), count(count), size(size) { } 1119 uint32_t index; // Index of the time interval that was changed. 1120 uint32_t count; // New value of count field for the interval with this index. 1121 uint32_t size; // New value of size field for the interval with this index. 1122 }; 1123 1124 #define CODE_EVENTS_LIST(V) \ 1125 V(Builtin) \ 1126 V(Callback) \ 1127 V(Eval) \ 1128 V(Function) \ 1129 V(InterpretedFunction) \ 1130 V(Handler) \ 1131 V(BytecodeHandler) \ 1132 V(LazyCompile) \ 1133 V(RegExp) \ 1134 V(Script) \ 1135 V(Stub) \ 1136 V(Relocation) 1137 1138 /** 1139 * Note that this enum may be extended in the future. Please include a default 1140 * case if this enum is used in a switch statement. 1141 */ 1142 enum CodeEventType { 1143 kUnknownType = 0 1144 #define V(Name) , k##Name##Type 1145 CODE_EVENTS_LIST(V) 1146 #undef V 1147 }; 1148 1149 /** 1150 * Representation of a code creation event 1151 */ 1152 class V8_EXPORT CodeEvent { 1153 public: 1154 uintptr_t GetCodeStartAddress(); 1155 size_t GetCodeSize(); 1156 Local<String> GetFunctionName(); 1157 Local<String> GetScriptName(); 1158 int GetScriptLine(); 1159 int GetScriptColumn(); 1160 /** 1161 * NOTE (mmarchini): We can't allocate objects in the heap when we collect 1162 * existing code, and both the code type and the comment are not stored in the 1163 * heap, so we return those as const char*. 1164 */ 1165 CodeEventType GetCodeType(); 1166 const char* GetComment(); 1167 1168 static const char* GetCodeEventTypeName(CodeEventType code_event_type); 1169 1170 uintptr_t GetPreviousCodeStartAddress(); 1171 }; 1172 1173 /** 1174 * Interface to listen to code creation and code relocation events. 1175 */ 1176 class V8_EXPORT CodeEventHandler { 1177 public: 1178 /** 1179 * Creates a new listener for the |isolate|. The isolate must be initialized. 1180 * The listener object must be disposed after use by calling |Dispose| method. 1181 * Multiple listeners can be created for the same isolate. 1182 */ 1183 explicit CodeEventHandler(Isolate* isolate); 1184 virtual ~CodeEventHandler(); 1185 1186 /** 1187 * Handle is called every time a code object is created or moved. Information 1188 * about each code event will be available through the `code_event` 1189 * parameter. 1190 * 1191 * When the CodeEventType is kRelocationType, the code for this CodeEvent has 1192 * moved from `GetPreviousCodeStartAddress()` to `GetCodeStartAddress()`. 1193 */ 1194 virtual void Handle(CodeEvent* code_event) = 0; 1195 1196 /** 1197 * Call `Enable()` to starts listening to code creation and code relocation 1198 * events. These events will be handled by `Handle()`. 1199 */ 1200 void Enable(); 1201 1202 /** 1203 * Call `Disable()` to stop listening to code creation and code relocation 1204 * events. 1205 */ 1206 void Disable(); 1207 1208 private: 1209 CodeEventHandler(); 1210 CodeEventHandler(const CodeEventHandler&); 1211 CodeEventHandler& operator=(const CodeEventHandler&); 1212 void* internal_listener_; 1213 }; 1214 1215 } // namespace v8 1216 1217 1218 #endif // V8_V8_PROFILER_H_ 1219