Coverage Report

Created: 2025-07-04 09:33

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