v8-profiler.h 35.9 KB
Newer Older
1
// Copyright 2010 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_V8_PROFILER_H_
#define V8_V8_PROFILER_H_

8
#include <unordered_set>
9
#include <vector>
10
#include "v8.h"  // NOLINT(build/include)
11 12 13 14 15 16

/**
 * Profiler support for the V8 JavaScript engine.
 */
namespace v8 {

17
class HeapGraphNode;
18
struct HeapStatsUpdate;
19

20
typedef uint32_t SnapshotObjectId;
21

22 23 24 25 26 27

struct CpuProfileDeoptFrame {
  int script_id;
  size_t position;
};

thakis's avatar
thakis committed
28
}  // namespace v8
29 30

#ifdef V8_OS_WIN
thakis's avatar
thakis committed
31
template class V8_EXPORT std::vector<v8::CpuProfileDeoptFrame>;
32 33
#endif

thakis's avatar
thakis committed
34
namespace v8 {
35 36 37 38 39 40 41

struct V8_EXPORT CpuProfileDeoptInfo {
  /** A pointer to a static string owned by v8. */
  const char* deopt_reason;
  std::vector<CpuProfileDeoptFrame> stack;
};

thakis's avatar
thakis committed
42
}  // namespace v8
43 44

#ifdef V8_OS_WIN
thakis's avatar
thakis committed
45
template class V8_EXPORT std::vector<v8::CpuProfileDeoptInfo>;
46 47
#endif

thakis's avatar
thakis committed
48
namespace v8 {
49

50 51
/**
 * TracingCpuProfiler monitors tracing being enabled/disabled
52
 * and emits CpuProfile trace events once v8.cpu_profiler tracing category
53 54 55 56
 * is enabled. It has no overhead unless the category is enabled.
 */
class V8_EXPORT TracingCpuProfiler {
 public:
57
  V8_DEPRECATED(
58 59 60 61
      "The profiler is created automatically with the isolate.\n"
      "No need to create it explicitly.",
      static std::unique_ptr<TracingCpuProfiler> Create(Isolate*));

62 63 64 65 66 67
  virtual ~TracingCpuProfiler() = default;

 protected:
  TracingCpuProfiler() = default;
};

68 69 70 71 72 73 74 75 76 77 78 79 80 81
// TickSample captures the information collected for each sample.
struct TickSample {
  // Internal profiling (with --prof + tools/$OS-tick-processor) wants to
  // include the runtime function we're calling. Externally exposed tick
  // samples don't care.
  enum RecordCEntryFrame { kIncludeCEntryFrame, kSkipCEntryFrame };

  TickSample()
      : state(OTHER),
        pc(nullptr),
        external_callback_entry(nullptr),
        frames_count(0),
        has_external_callback(false),
        update_stats(true) {}
82 83 84 85 86 87 88 89 90 91 92 93 94

  /**
   * Initialize a tick sample from the isolate.
   * \param isolate The isolate.
   * \param state Execution state.
   * \param record_c_entry_frame Include or skip the runtime function.
   * \param update_stats Whether update the sample to the aggregated stats.
   * \param use_simulator_reg_state When set to true and V8 is running under a
   *                                simulator, the method will use the simulator
   *                                register state rather than the one provided
   *                                with |state| argument. Otherwise the method
   *                                will use provided register |state| as is.
   */
95
  void Init(Isolate* isolate, const v8::RegisterState& state,
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
            RecordCEntryFrame record_c_entry_frame, bool update_stats,
            bool use_simulator_reg_state = true);
  /**
   * Get a call stack sample from the isolate.
   * \param isolate The isolate.
   * \param state Register state.
   * \param record_c_entry_frame Include or skip the runtime function.
   * \param frames Caller allocated buffer to store stack frames.
   * \param frames_limit Maximum number of frames to capture. The buffer must
   *                     be large enough to hold the number of frames.
   * \param sample_info The sample info is filled up by the function
   *                    provides number of actual captured stack frames and
   *                    the current VM state.
   * \param use_simulator_reg_state When set to true and V8 is running under a
   *                                simulator, the method will use the simulator
   *                                register state rather than the one provided
   *                                with |state| argument. Otherwise the method
   *                                will use provided register |state| as is.
   * \note GetStackSample is thread and signal safe and should only be called
   *                      when the JS thread is paused or interrupted.
   *                      Otherwise the behavior is undefined.
   */
  static bool GetStackSample(Isolate* isolate, v8::RegisterState* state,
119 120
                             RecordCEntryFrame record_c_entry_frame,
                             void** frames, size_t frames_limit,
121 122
                             v8::SampleInfo* sample_info,
                             bool use_simulator_reg_state = true);
123 124 125 126 127 128 129 130 131 132 133 134 135 136
  StateTag state;  // The state of the VM.
  void* pc;        // Instruction pointer.
  union {
    void* tos;  // Top stack value (*sp).
    void* external_callback_entry;
  };
  static const unsigned kMaxFramesCountLog2 = 8;
  static const unsigned kMaxFramesCount = (1 << kMaxFramesCountLog2) - 1;
  void* stack[kMaxFramesCount];                 // Call stack.
  unsigned frames_count : kMaxFramesCountLog2;  // Number of captured frames.
  bool has_external_callback : 1;
  bool update_stats : 1;  // Whether the sample should update aggregated stats.
};

137 138 139
/**
 * CpuProfileNode represents a node in a call graph.
 */
140
class V8_EXPORT CpuProfileNode {
141
 public:
142 143 144 145 146 147 148 149
  struct LineTick {
    /** The 1-based number of the source line where the function originates. */
    int line;

    /** The count of samples associated with the source line. */
    unsigned int hit_count;
  };

150
  /** Returns function name (empty string for anonymous functions.) */
151
  Local<String> GetFunctionName() const;
152

153 154 155 156 157 158 159
  /**
   * Returns function name (empty string for anonymous functions.)
   * The string ownership is *not* passed to the caller. It stays valid until
   * profile is deleted. The function is thread safe.
   */
  const char* GetFunctionNameStr() const;

160 161 162
  /** Returns id of the script where function is located. */
  int GetScriptId() const;

163
  /** Returns resource name for script from where the function originates. */
164
  Local<String> GetScriptResourceName() const;
165

166 167 168 169 170 171 172
  /**
   * Returns resource name for script from where the function originates.
   * The string ownership is *not* passed to the caller. It stays valid until
   * profile is deleted. The function is thread safe.
   */
  const char* GetScriptResourceNameStr() const;

173 174 175 176 177 178
  /**
   * Returns the number, 1-based, of the line where the function originates.
   * kNoLineNumberInfo if no line number information is available.
   */
  int GetLineNumber() const;

179 180 181 182 183 184
  /**
   * Returns 1-based number of the column where the function originates.
   * kNoColumnNumberInfo if no column number information is available.
   */
  int GetColumnNumber() const;

185 186 187 188 189 190 191 192 193 194 195 196
  /**
   * Returns the number of the function's source lines that collect the samples.
   */
  unsigned int GetHitLineCount() const;

  /** Returns the set of source lines that collect the samples.
   *  The caller allocates buffer and responsible for releasing it.
   *  True if all available entries are copied, otherwise false.
   *  The function copies nothing if buffer is not large enough.
   */
  bool GetLineTicks(LineTick* entries, unsigned int length) const;

197 198 199 200 201
  /** Returns bailout reason for the function
    * if the optimization was disabled for it.
    */
  const char* GetBailoutReason() const;

202 203 204 205 206
  /**
    * Returns the count of samples where the function was currently executing.
    */
  unsigned GetHitCount() const;

207
  /** Returns function entry UID. */
208 209 210
  V8_DEPRECATE_SOON(
      "Use GetScriptId, GetLineNumber, and GetColumnNumber instead.",
      unsigned GetCallUid() const);
211

212 213 214
  /** Returns id of the node. The id is unique within the tree */
  unsigned GetNodeId() const;

215 216 217 218 219 220
  /** Returns child nodes count of the node. */
  int GetChildrenCount() const;

  /** Retrieves a child node by index. */
  const CpuProfileNode* GetChild(int index) const;

221 222 223
  /** Retrieves deopt infos for the node. */
  const std::vector<CpuProfileDeoptInfo>& GetDeoptInfos() const;

224
  static const int kNoLineNumberInfo = Message::kNoLineNumberInfo;
225
  static const int kNoColumnNumberInfo = Message::kNoColumnInfo;
226 227 228 229
};


/**
230 231
 * CpuProfile contains a CPU profile in a form of top-down call tree
 * (from main() down to functions that do all the work).
232
 */
233
class V8_EXPORT CpuProfile {
234 235
 public:
  /** Returns CPU profile title. */
236
  Local<String> GetTitle() const;
237 238 239

  /** Returns the root node of the top down call tree. */
  const CpuProfileNode* GetTopDownRoot() const;
240

241
  /**
242 243 244
   * Returns number of samples recorded. The samples are not recorded unless
   * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true.
   */
245 246 247
  int GetSamplesCount() const;

  /**
248 249 250
   * Returns profile node corresponding to the top frame the sample at
   * the given index.
   */
251 252
  const CpuProfileNode* GetSample(int index) const;

253
  /**
254 255 256 257 258 259 260 261 262 263
   * Returns the timestamp of the sample. The timestamp is the number of
   * microseconds since some unspecified starting point.
   * The point is equal to the starting point used by GetStartTime.
   */
  int64_t GetSampleTimestamp(int index) const;

  /**
   * Returns time when the profile recording was started (in microseconds)
   * since some unspecified starting point.
   */
264
  int64_t GetStartTime() const;
265 266

  /**
267 268 269 270
   * Returns time when the profile recording was stopped (in microseconds)
   * since some unspecified starting point.
   * The point is equal to the starting point used by GetStartTime.
   */
271
  int64_t GetEndTime() const;
272

273 274 275 276 277
  /**
   * Deletes the profile and removes it from CpuProfiler's list.
   * All pointers to nodes previously returned become invalid.
   */
  void Delete();
278 279
};

280 281 282 283 284 285 286 287 288 289
enum CpuProfilingMode {
  // In the resulting CpuProfile tree, intermediate nodes in a stack trace
  // (from the root to a leaf) will have line numbers that point to the start
  // line of the function, rather than the line of the callsite of the child.
  kLeafNodeLineNumbers,
  // In the resulting CpuProfile tree, nodes are separated based on the line
  // number of their callsite in their parent.
  kCallerLineNumbers,
};

290
/**
291
 * Interface for controlling CPU profiling. Instance of the
292
 * profiler can be created using v8::CpuProfiler::New method.
293
 */
294
class V8_EXPORT CpuProfiler {
295
 public:
296 297 298 299 300 301 302
  /**
   * Creates a new CPU profiler for the |isolate|. The isolate must be
   * initialized. The profiler object must be disposed after use by calling
   * |Dispose| method.
   */
  static CpuProfiler* New(Isolate* isolate);

303 304 305 306 307 308 309
  /**
   * Synchronously collect current stack sample in all profilers attached to
   * the |isolate|. The call does not affect number of ticks recorded for
   * the current top node.
   */
  static void CollectSample(Isolate* isolate);

310 311 312 313 314
  /**
   * Disposes the CPU profiler object.
   */
  void Dispose();

315
  /**
316 317 318
   * Changes default CPU profiler sampling interval to the specified number
   * of microseconds. Default interval is 1000us. This method must be called
   * when there are no profiles being recorded.
319
   */
320
  void SetSamplingInterval(int us);
321

322 323 324 325
  /**
   * Starts collecting CPU profile. Title may be an empty string. It
   * is allowed to have several profiles being collected at
   * once. Attempts to start collecting several profiles with the same
326 327 328
   * title are silently ignored. While collecting a profile, functions
   * from all security contexts are included in it. The token-based
   * filtering is only performed when querying for a profile.
329 330 331
   *
   * |record_samples| parameter controls whether individual samples should
   * be recorded in addition to the aggregated tree.
332
   */
333 334 335 336 337 338 339
  void StartProfiling(Local<String> title, CpuProfilingMode mode,
                      bool record_samples = false);
  /**
   * The same as StartProfiling above, but the CpuProfilingMode defaults to
   * kLeafNodeLineNumbers mode, which was the previous default behavior of the
   * profiler.
   */
340
  void StartProfiling(Local<String> title, bool record_samples = false);
341

342 343 344 345
  /**
   * Stops collecting CPU profile with a given title and returns it.
   * If the title given is empty, finishes the last profile started.
   */
346
  CpuProfile* StopProfiling(Local<String> title);
347

348 349 350 351 352
  /**
   * Force collection of a sample. Must be called on the VM thread.
   * Recording the forced sample does not contribute to the aggregated
   * profile statistics.
   */
353 354
  V8_DEPRECATED("Use static CollectSample(Isolate*) instead.",
                void CollectSample());
355

356 357 358
  /**
   * Tells the profiler whether the embedder is idle.
   */
359 360
  V8_DEPRECATED("Use Isolate::SetIdle(bool) instead.",
                void SetIdle(bool is_idle));
361

362 363 364 365 366
 private:
  CpuProfiler();
  ~CpuProfiler();
  CpuProfiler(const CpuProfiler&);
  CpuProfiler& operator=(const CpuProfiler&);
367 368 369
};


370 371
/**
 * HeapSnapshotEdge represents a directed connection between heap
372
 * graph nodes: from retainers to retained nodes.
373
 */
374
class V8_EXPORT HeapGraphEdge {
375 376
 public:
  enum Type {
377 378 379
    kContextVariable = 0,  // A variable from a function context.
    kElement = 1,          // An element of an array.
    kProperty = 2,         // A named object property.
380 381 382 383 384
    kInternal = 3,         // A link that can't be accessed from JS,
                           // thus, its name isn't a real property name
                           // (e.g. parts of a ConsString).
    kHidden = 4,           // A link that is needed for proper sizes
                           // calculation, but may be hidden from user.
385
    kShortcut = 5,         // A link that must not be followed during
386
                           // sizes calculation.
387
    kWeak = 6              // A weak reference (ignored by the GC).
388 389 390 391 392 393 394 395 396
  };

  /** Returns edge type (see HeapGraphEdge::Type). */
  Type GetType() const;

  /**
   * Returns edge name. This can be a variable name, an element index, or
   * a property name.
   */
397
  Local<Value> GetName() const;
398 399 400 401 402 403 404 405 406 407 408 409

  /** Returns origin node. */
  const HeapGraphNode* GetFromNode() const;

  /** Returns destination node. */
  const HeapGraphNode* GetToNode() const;
};


/**
 * HeapGraphNode represents a node in a heap graph.
 */
410
class V8_EXPORT HeapGraphNode {
411 412
 public:
  enum Type {
413 414 415 416 417 418 419 420 421
    kHidden = 0,         // Hidden node, may be filtered when shown to user.
    kArray = 1,          // An array of elements.
    kString = 2,         // A string.
    kObject = 3,         // A JS object (except for arrays and strings).
    kCode = 4,           // Compiled code.
    kClosure = 5,        // Function closure.
    kRegExp = 6,         // RegExp.
    kHeapNumber = 7,     // Number stored in the heap.
    kNative = 8,         // Native object (not from V8 heap).
422
    kSynthetic = 9,      // Synthetic object, usually used for grouping
423 424 425
                         // snapshot items together.
    kConsString = 10,    // Concatenated string. A pair of pointers to strings.
    kSlicedString = 11,  // Sliced string. A fragment of another string.
426 427
    kSymbol = 12,        // A Symbol (ES6).
    kBigInt = 13         // BigInt.
428 429 430 431 432 433 434 435 436 437
  };

  /** Returns node type (see HeapGraphNode::Type). */
  Type GetType() const;

  /**
   * Returns node name. Depending on node's type this can be the name
   * of the constructor (for objects), the name of the function (for
   * closures), string value, or an empty string (for compiled code).
   */
438
  Local<String> GetName() const;
439

440 441
  /**
   * Returns node id. For the same heap object, the id remains the same
442
   * across all snapshots.
443
   */
444
  SnapshotObjectId GetId() const;
445

446 447
  /** Returns node's own size, in bytes. */
  size_t GetShallowSize() const;
448 449 450 451 452 453 454 455 456

  /** Returns child nodes count of the node. */
  int GetChildrenCount() const;

  /** Retrieves a child by index. */
  const HeapGraphEdge* GetChild(int index) const;
};


457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
/**
 * An interface for exporting data from V8, using "push" model.
 */
class V8_EXPORT OutputStream {  // NOLINT
 public:
  enum WriteResult {
    kContinue = 0,
    kAbort = 1
  };
  virtual ~OutputStream() {}
  /** Notify about the end of stream. */
  virtual void EndOfStream() = 0;
  /** Get preferred output chunk size. Called only once. */
  virtual int GetChunkSize() { return 1024; }
  /**
   * Writes the next chunk of snapshot data into the stream. Writing
   * can be stopped by returning kAbort as function result. EndOfStream
   * will not be called in case writing was aborted.
   */
  virtual WriteResult WriteAsciiChunk(char* data, int size) = 0;
  /**
   * Writes the next chunk of heap stats data into the stream. Writing
   * can be stopped by returning kAbort as function result. EndOfStream
   * will not be called in case writing was aborted.
   */
  virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) {
    return kAbort;
484
  }
485 486 487
};


488 489 490
/**
 * HeapSnapshots record the state of the JS heap at some moment.
 */
491
class V8_EXPORT HeapSnapshot {
492
 public:
493 494
  enum SerializationFormat {
    kJSON = 0  // See format description near 'Serialize' method.
495 496
  };

497
  /** Returns the root node of the heap graph. */
498 499
  const HeapGraphNode* GetRoot() const;

500
  /** Returns a node by its id. */
501
  const HeapGraphNode* GetNodeById(SnapshotObjectId id) const;
502

503 504 505 506 507 508
  /** Returns total nodes count in the snapshot. */
  int GetNodesCount() const;

  /** Returns a node by index. */
  const HeapGraphNode* GetNode(int index) const;

509 510 511
  /** Returns a max seen JS object Id. */
  SnapshotObjectId GetMaxSnapshotJSObjectId() const;

512 513 514 515 516 517 518
  /**
   * Deletes the snapshot and removes it from HeapProfiler's list.
   * All pointers to nodes, edges and paths previously returned become
   * invalid.
   */
  void Delete();

519 520 521 522
  /**
   * Prepare a serialized representation of the snapshot. The result
   * is written into the stream provided in chunks of specified size.
   * The total length of the serialized snapshot is unknown in
523
   * advance, it can be roughly equal to JS heap size (that means,
524 525 526 527 528 529
   * it can be really big - tens of megabytes).
   *
   * For the JSON format, heap contents are represented as an object
   * with the following structure:
   *
   *  {
530 531 532 533 534 535 536 537 538 539
   *    snapshot: {
   *      title: "...",
   *      uid: nnn,
   *      meta: { meta-info },
   *      node_count: nnn,
   *      edge_count: nnn
   *    },
   *    nodes: [nodes array],
   *    edges: [edges array],
   *    strings: [strings array]
540 541
   *  }
   *
542 543
   * Nodes reference strings, other nodes, and edges by their indexes
   * in corresponding arrays.
544
   */
545 546
  void Serialize(OutputStream* stream,
                 SerializationFormat format = kJSON) const;
547 548 549
};


550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
/**
 * An interface for reporting progress and controlling long-running
 * activities.
 */
class V8_EXPORT ActivityControl {  // NOLINT
 public:
  enum ControlOption {
    kContinue = 0,
    kAbort = 1
  };
  virtual ~ActivityControl() {}
  /**
   * Notify about current progress. The activity can be stopped by
   * returning kAbort as the callback result.
   */
  virtual ControlOption ReportProgressValue(int done, int total) = 0;
};

568

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
/**
 * AllocationProfile is a sampled profile of allocations done by the program.
 * This is structured as a call-graph.
 */
class V8_EXPORT AllocationProfile {
 public:
  struct Allocation {
    /**
     * Size of the sampled allocation object.
     */
    size_t size;

    /**
     * The number of objects of such size that were sampled.
     */
    unsigned int count;
  };

  /**
   * Represents a node in the call-graph.
   */
  struct Node {
    /**
     * Name of the function. May be empty for anonymous functions or if the
     * script corresponding to this function has been unloaded.
     */
    Local<String> name;

    /**
     * Name of the script containing the function. May be empty if the script
     * name is not available, or if the script has been unloaded.
     */
    Local<String> script_name;

    /**
     * id of the script where the function is located. May be equal to
     * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist.
     */
    int script_id;

    /**
     * Start position of the function in the script.
     */
    int start_position;

    /**
     * 1-indexed line number where the function starts. May be
     * kNoLineNumberInfo if no line number information is available.
     */
    int line_number;

    /**
     * 1-indexed column number where the function starts. May be
     * kNoColumnNumberInfo if no line number information is available.
     */
    int column_number;

    /**
     * List of callees called from this node for which we have sampled
     * allocations. The lifetime of the children is scoped to the containing
     * AllocationProfile.
     */
    std::vector<Node*> children;

    /**
     * List of self allocations done by this node in the call-graph.
     */
    std::vector<Allocation> allocations;
  };

  /**
   * Returns the root node of the call-graph. The root node corresponds to an
   * empty JS call-stack. The lifetime of the returned Node* is scoped to the
   * containing AllocationProfile.
   */
  virtual Node* GetRootNode() = 0;

  virtual ~AllocationProfile() {}

  static const int kNoLineNumberInfo = Message::kNoLineNumberInfo;
  static const int kNoColumnNumberInfo = Message::kNoColumnInfo;
};

652 653 654 655 656 657 658 659
/**
 * An object graph consisting of embedder objects and V8 objects.
 * Edges of the graph are strong references between the objects.
 * The embedder can build this graph during heap snapshot generation
 * to include the embedder objects in the heap snapshot.
 * Usage:
 * 1) Define derived class of EmbedderGraph::Node for embedder objects.
 * 2) Set the build embedder graph callback on the heap profiler using
660
 *    HeapProfiler::AddBuildEmbedderGraphCallback.
661 662 663 664 665 666 667 668 669 670 671 672 673
 * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from
 *    node1 to node2.
 * 4) To represent references from/to V8 object, construct V8 nodes using
 *    graph->V8Node(value).
 */
class V8_EXPORT EmbedderGraph {
 public:
  class Node {
   public:
    Node() = default;
    virtual ~Node() = default;
    virtual const char* Name() = 0;
    virtual size_t SizeInBytes() = 0;
674 675 676 677 678 679
    /**
     * The corresponding V8 wrapper node if not null.
     * During heap snapshot generation the embedder node and the V8 wrapper
     * node will be merged into one node to simplify retaining paths.
     */
    virtual Node* WrapperNode() { return nullptr; }
680 681 682
    virtual bool IsRootNode() { return false; }
    /** Must return true for non-V8 nodes. */
    virtual bool IsEmbedderNode() { return true; }
683 684 685 686
    /**
     * Optional name prefix. It is used in Chrome for tagging detached nodes.
     */
    virtual const char* NamePrefix() { return nullptr; }
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713

   private:
    Node(const Node&) = delete;
    Node& operator=(const Node&) = delete;
  };

  /**
   * Returns a node corresponding to the given V8 value. Ownership is not
   * transferred. The result pointer is valid while the graph is alive.
   */
  virtual Node* V8Node(const v8::Local<v8::Value>& value) = 0;

  /**
   * Adds the given node to the graph and takes ownership of the node.
   * Returns a raw pointer to the node that is valid while the graph is alive.
   */
  virtual Node* AddNode(std::unique_ptr<Node> node) = 0;

  /**
   * Adds an edge that represents a strong reference from the given node
   * |from| to the given node |to|. The nodes must be added to the graph
   * before calling this function.
   */
  virtual void AddEdge(Node* from, Node* to) = 0;

  virtual ~EmbedderGraph() = default;
};
714

715
/**
716 717
 * Interface for controlling heap profiling. Instance of the
 * profiler can be retrieved using v8::Isolate::GetHeapProfiler.
718
 */
719
class V8_EXPORT HeapProfiler {
720
 public:
721 722 723 724 725
  enum SamplingFlags {
    kSamplingNoFlags = 0,
    kSamplingForceGC = 1 << 0,
  };

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
  typedef std::unordered_set<const v8::PersistentBase<v8::Value>*>
      RetainerChildren;
  typedef std::vector<std::pair<v8::RetainedObjectInfo*, RetainerChildren>>
      RetainerGroups;
  typedef std::vector<std::pair<const v8::PersistentBase<v8::Value>*,
                                const v8::PersistentBase<v8::Value>*>>
      RetainerEdges;

  struct RetainerInfos {
    RetainerGroups groups;
    RetainerEdges edges;
  };

  /**
   * Callback function invoked to retrieve all RetainerInfos from the embedder.
   */
  typedef RetainerInfos (*GetRetainerInfosCallback)(v8::Isolate* isolate);

744 745 746 747 748 749
  /**
   * Callback function invoked for obtaining RetainedObjectInfo for
   * the given JavaScript wrapper object. It is prohibited to enter V8
   * while the callback is running: only getters on the handle and
   * GetPointerFromInternalField on the objects are allowed.
   */
750 751
  typedef RetainedObjectInfo* (*WrapperInfoCallback)(uint16_t class_id,
                                                     Local<Value> wrapper);
752

753 754 755 756 757 758 759
  /**
   * Callback function invoked during heap snapshot generation to retrieve
   * the embedder object graph. The callback should use graph->AddEdge(..) to
   * add references between the objects.
   * The callback must not trigger garbage collection in V8.
   */
  typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate,
760 761 762 763 764 765
                                             v8::EmbedderGraph* graph,
                                             void* data);

  /** TODO(addaleax): Remove */
  typedef void (*LegacyBuildEmbedderGraphCallback)(v8::Isolate* isolate,
                                                   v8::EmbedderGraph* graph);
766

767 768
  /** Returns the number of snapshots taken. */
  int GetSnapshotCount();
769

770 771
  /** Returns a snapshot by index. */
  const HeapSnapshot* GetHeapSnapshot(int index);
772

773 774 775 776
  /**
   * Returns SnapshotObjectId for a heap object referenced by |value| if
   * it has been seen by the heap profiler, kUnknownObjectId otherwise.
   */
777
  SnapshotObjectId GetObjectId(Local<Value> value);
778

779 780 781 782
  /**
   * Returns heap object with given SnapshotObjectId if the object is alive,
   * otherwise empty handle is returned.
   */
783
  Local<Value> FindObjectById(SnapshotObjectId id);
784 785 786 787 788 789 790 791

  /**
   * Clears internal map from SnapshotObjectId to heap object. The new objects
   * will not be added into it unless a heap snapshot is taken or heap object
   * tracking is kicked off.
   */
  void ClearObjectIds();

792 793 794 795 796
  /**
   * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return
   * it in case heap profiler cannot find id  for the object passed as
   * parameter. HeapSnapshot::GetNodeById will always return NULL for such id.
   */
797
  static const SnapshotObjectId kUnknownObjectId = 0;
798

799 800 801 802
  /**
   * Callback interface for retrieving user friendly names of global objects.
   */
  class ObjectNameResolver {
803
   public:
804 805 806 807
    /**
     * Returns name to be used in the heap snapshot for given node. Returned
     * string must stay alive until snapshot collection is completed.
     */
808 809
    virtual const char* GetName(Local<Object> object) = 0;

810
   protected:
811 812 813
    virtual ~ObjectNameResolver() {}
  };

814
  /**
815
   * Takes a heap snapshot and returns it.
816
   */
817 818 819 820
  const HeapSnapshot* TakeHeapSnapshot(
      ActivityControl* control = NULL,
      ObjectNameResolver* global_object_name_resolver = NULL);

821 822 823 824
  /**
   * Starts tracking of heap objects population statistics. After calling
   * this method, all heap objects relocations done by the garbage collector
   * are being registered.
825 826 827 828
   *
   * |track_allocations| parameter controls whether stack trace of each
   * allocation in the heap will be recorded and reported as part of
   * HeapSnapshot.
829
   */
830
  void StartTrackingHeapObjects(bool track_allocations = false);
831 832 833 834 835 836

  /**
   * Adds a new time interval entry to the aggregated statistics array. The
   * time interval entry contains information on the current heap objects
   * population size. The method also updates aggregated statistics and
   * reports updates for all previous time intervals via the OutputStream
837 838
   * object. Updates on each time interval are provided as a stream of the
   * HeapStatsUpdate structure instances.
839 840
   * If |timestamp_us| is supplied, timestamp of the new entry will be written
   * into it. The return value of the function is the last seen heap object Id.
841
   *
842
   * StartTrackingHeapObjects must be called before the first call to this
843 844
   * method.
   */
845 846
  SnapshotObjectId GetHeapStats(OutputStream* stream,
                                int64_t* timestamp_us = NULL);
847 848 849 850

  /**
   * Stops tracking of heap objects population statistics, cleans up all
   * collected data. StartHeapObjectsTracking must be called again prior to
851
   * calling GetHeapStats next time.
852
   */
853
  void StopTrackingHeapObjects();
854

855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882
  /**
   * Starts gathering a sampling heap profile. A sampling heap profile is
   * similar to tcmalloc's heap profiler and Go's mprof. It samples object
   * allocations and builds an online 'sampling' heap profile. At any point in
   * time, this profile is expected to be a representative sample of objects
   * currently live in the system. Each sampled allocation includes the stack
   * trace at the time of allocation, which makes this really useful for memory
   * leak detection.
   *
   * This mechanism is intended to be cheap enough that it can be used in
   * production with minimal performance overhead.
   *
   * Allocations are sampled using a randomized Poisson process. On average, one
   * allocation will be sampled every |sample_interval| bytes allocated. The
   * |stack_depth| parameter controls the maximum number of stack frames to be
   * captured on each allocation.
   *
   * NOTE: This is a proof-of-concept at this point. Right now we only sample
   * newspace allocations. Support for paged space allocation (e.g. pre-tenured
   * objects, large objects, code objects, etc.) and native allocations
   * doesn't exist yet, but is anticipated in the future.
   *
   * Objects allocated before the sampling is started will not be included in
   * the profile.
   *
   * Returns false if a sampling heap profiler is already running.
   */
  bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024,
883 884
                                 int stack_depth = 16,
                                 SamplingFlags flags = kSamplingNoFlags);
885 886 887 888 889 890 891 892 893

  /**
   * Stops the sampling heap profile and discards the current profile.
   */
  void StopSamplingHeapProfiler();

  /**
   * Returns the sampled profile of allocations allocated (and still live) since
   * StartSamplingHeapProfiler was called. The ownership of the pointer is
894
   * transferred to the caller. Returns nullptr if sampling heap profiler is not
895 896 897 898
   * active.
   */
  AllocationProfile* GetAllocationProfile();

899 900 901 902
  /**
   * Deletes all snapshots taken. All previously returned pointers to
   * snapshots and their contents become invalid after this call.
   */
903
  void DeleteAllHeapSnapshots();
904

905
  /** Binds a callback to embedder's class ID. */
906
  V8_DEPRECATED(
907
      "Use AddBuildEmbedderGraphCallback to provide info about embedder nodes",
908 909
      void SetWrapperClassInfoProvider(uint16_t class_id,
                                       WrapperInfoCallback callback));
910 911

  V8_DEPRECATED(
912
      "Use AddBuildEmbedderGraphCallback to provide info about embedder nodes",
913
      void SetGetRetainerInfosCallback(GetRetainerInfosCallback callback));
914

915 916 917 918 919 920 921 922
  V8_DEPRECATE_SOON(
      "Use AddBuildEmbedderGraphCallback to provide info about embedder nodes",
      void SetBuildEmbedderGraphCallback(
          LegacyBuildEmbedderGraphCallback callback));
  void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback,
                                     void* data);
  void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback,
                                        void* data);
923

924 925 926 927 928 929
  /**
   * Default value of persistent handle class ID. Must not be used to
   * define a class. Can be used to reset a class of a persistent
   * handle.
   */
  static const uint16_t kPersistentHandleNoClassId = 0;
930

931 932 933 934 935
 private:
  HeapProfiler();
  ~HeapProfiler();
  HeapProfiler(const HeapProfiler&);
  HeapProfiler& operator=(const HeapProfiler&);
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
};

/**
 * Interface for providing information about embedder's objects
 * held by global handles. This information is reported in two ways:
 *
 *  1. When calling AddObjectGroup, an embedder may pass
 *     RetainedObjectInfo instance describing the group.  To collect
 *     this information while taking a heap snapshot, V8 calls GC
 *     prologue and epilogue callbacks.
 *
 *  2. When a heap snapshot is collected, V8 additionally
 *     requests RetainedObjectInfos for persistent handles that
 *     were not previously reported via AddObjectGroup.
 *
 * Thus, if an embedder wants to provide information about native
hlopko's avatar
hlopko committed
952
 * objects for heap snapshots, it can do it in a GC prologue
953 954
 * handler, and / or by assigning wrapper class ids in the following way:
 *
955
 *  1. Bind a callback to class id by calling SetWrapperClassInfoProvider.
956 957 958 959 960 961
 *  2. Call SetWrapperClassId on certain persistent handles.
 *
 * V8 takes ownership of RetainedObjectInfo instances passed to it and
 * keeps them alive only during snapshot collection. Afterwards, they
 * are freed by calling the Dispose class function.
 */
962
class V8_EXPORT RetainedObjectInfo {  // NOLINT
963 964 965 966 967 968 969 970 971 972 973 974 975 976
 public:
  /** Called by V8 when it no longer needs an instance. */
  virtual void Dispose() = 0;

  /** Returns whether two instances are equivalent. */
  virtual bool IsEquivalent(RetainedObjectInfo* other) = 0;

  /**
   * Returns hash value for the instance. Equivalent instances
   * must have the same hash value.
   */
  virtual intptr_t GetHash() = 0;

  /**
977
   * Returns human-readable label. It must be a null-terminated UTF-8
978 979 980 981
   * encoded string. V8 copies its contents during a call to GetLabel.
   */
  virtual const char* GetLabel() = 0;

982 983 984 985 986 987 988 989 990 991 992
  /**
   * Returns human-readable group label. It must be a null-terminated UTF-8
   * encoded string. V8 copies its contents during a call to GetGroupLabel.
   * Heap snapshot generator will collect all the group names, create
   * top level entries with these names and attach the objects to the
   * corresponding top level group objects. There is a default
   * implementation which is required because embedders don't have their
   * own implementation yet.
   */
  virtual const char* GetGroupLabel() { return GetLabel(); }

993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
  /**
   * Returns element count in case if a global handle retains
   * a subgraph by holding one of its nodes.
   */
  virtual intptr_t GetElementCount() { return -1; }

  /** Returns embedder's object size in bytes. */
  virtual intptr_t GetSizeInBytes() { return -1; }

 protected:
  RetainedObjectInfo() {}
  virtual ~RetainedObjectInfo() {}

 private:
  RetainedObjectInfo(const RetainedObjectInfo&);
  RetainedObjectInfo& operator=(const RetainedObjectInfo&);
1009 1010 1011
};


1012 1013
/**
 * A struct for exporting HeapStats data from V8, using "push" model.
1014
 * See HeapProfiler::GetHeapStats.
1015 1016 1017 1018 1019 1020 1021 1022 1023
 */
struct HeapStatsUpdate {
  HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size)
    : index(index), count(count), size(size) { }
  uint32_t index;  // Index of the time interval that was changed.
  uint32_t count;  // New value of count field for the interval with this index.
  uint32_t size;  // New value of size field for the interval with this index.
};

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
#define CODE_EVENTS_LIST(V) \
  V(Builtin)                \
  V(Callback)               \
  V(Eval)                   \
  V(Function)               \
  V(InterpretedFunction)    \
  V(Handler)                \
  V(BytecodeHandler)        \
  V(LazyCompile)            \
  V(RegExp)                 \
  V(Script)                 \
  V(Stub)

/**
 * Note that this enum may be extended in the future. Please include a default
 * case if this enum is used in a switch statement.
 */
enum CodeEventType {
  kUnknownType = 0
#define V(Name) , k##Name##Type
  CODE_EVENTS_LIST(V)
#undef V
};

/**
 * Representation of a code creation event
 */
class V8_EXPORT CodeEvent {
 public:
  uintptr_t GetCodeStartAddress();
  size_t GetCodeSize();
  Local<String> GetFunctionName();
  Local<String> GetScriptName();
  int GetScriptLine();
  int GetScriptColumn();
  /**
   * NOTE (mmarchini): We can't allocate objects in the heap when we collect
   * existing code, and both the code type and the comment are not stored in the
   * heap, so we return those as const char*.
   */
  CodeEventType GetCodeType();
  const char* GetComment();

  static const char* GetCodeEventTypeName(CodeEventType code_event_type);
};

/**
 * Interface to listen to code creation events.
 */
class V8_EXPORT CodeEventHandler {
 public:
  /**
   * Creates a new listener for the |isolate|. The isolate must be initialized.
   * The listener object must be disposed after use by calling |Dispose| method.
   * Multiple listeners can be created for the same isolate.
   */
  explicit CodeEventHandler(Isolate* isolate);
  virtual ~CodeEventHandler();

  virtual void Handle(CodeEvent* code_event) = 0;

  void Enable();
  void Disable();

 private:
  CodeEventHandler();
  CodeEventHandler(const CodeEventHandler&);
  CodeEventHandler& operator=(const CodeEventHandler&);
  void* internal_listener_;
};
1094

1095 1096 1097 1098
}  // namespace v8


#endif  // V8_V8_PROFILER_H_