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