v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
cpu-profiler.h
Go to the documentation of this file.
1// Copyright 2012 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_PROFILER_CPU_PROFILER_H_
6#define V8_PROFILER_CPU_PROFILER_H_
7
8#include <atomic>
9#include <memory>
10
18
19#if V8_OS_WIN
21#endif
22
23namespace v8 {
24namespace sampler {
25class Sampler;
26} // namespace sampler
27namespace internal {
28
29// Forward declarations.
30class CodeEntry;
31class InstructionStreamMap;
32class CpuProfilesCollection;
33class Isolate;
34class Symbolizer;
35
36#define CODE_EVENTS_TYPE_LIST(V) \
37 V(kCodeCreation, CodeCreateEventRecord) \
38 V(kCodeMove, CodeMoveEventRecord) \
39 V(kCodeDisableOpt, CodeDisableOptEventRecord) \
40 V(kCodeDeopt, CodeDeoptEventRecord) \
41 V(kReportBuiltin, ReportBuiltinEventRecord) \
42 V(kCodeDelete, CodeDeleteEventRecord)
43
44#define VM_EVENTS_TYPE_LIST(V) \
45 CODE_EVENTS_TYPE_LIST(V) \
46 V(kNativeContextMove, NativeContextMoveEventRecord)
47
49 public:
50#define DECLARE_TYPE(type, ignore) type,
52#undef DECLARE_TYPE
53
55 mutable unsigned order;
56};
57
58
67
68
76
77
79 public:
81 const char* bailout_reason;
82
83 V8_INLINE void UpdateCodeMap(InstructionStreamMap* instruction_stream_map);
84};
85
86
99
100
109
110// Signals that a native context's address has changed.
116
117// A record type for sending samples from the main thread/signal handler to the
118// profiling thread.
120 public:
121 // The parameterless constructor is used when we dequeue data from
122 // the ticks buffer.
124 explicit TickSampleEventRecord(unsigned order) : order(order) { }
125
126 unsigned order;
128};
129
131 public:
133
134 V8_INLINE void UpdateCodeMap(InstructionStreamMap* instruction_stream_map);
135};
136
137// A record type for sending code events (e.g. create, move, delete) to the
138// profiling thread.
140 public:
143 generic.type = type;
144 }
145 union {
147#define DECLARE_CLASS(ignore, type) type type##_;
149#undef DECLARE_CLASS
150 };
151};
152
153// Maintains the number of active CPU profilers in an isolate, and routes
154// logging to a given ProfilerListener.
156 public:
157 ProfilingScope(Isolate* isolate, ProfilerListener* listener);
159
160 private:
163};
164
166
167// This class implements both the profile events processor thread and
168// methods called by event producers: VM and stack sampler threads.
170 public CodeEventObserver {
171 public:
172 ~ProfilerEventsProcessor() override;
173
174 void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
175
176 // Thread control.
177 void Run() override = 0;
178 void StopSynchronously();
179 bool running() { return running_.load(std::memory_order_relaxed); }
180 void Enqueue(const CodeEventsContainer& event);
181
182 // Puts current stack into the tick sample events buffer.
183 void AddCurrentStack(bool update_stats = false,
184 const std::optional<uint64_t> trace_id = std::nullopt);
185 void AddDeoptStack(Address from, int fp_to_sp_delta);
186 // Add a sample into the tick sample events buffer. Used for testing.
187 void AddSample(TickSample sample);
188
190
191 protected:
192 ProfilerEventsProcessor(Isolate* isolate, Symbolizer* symbolizer,
193 ProfilerCodeObserver* code_observer,
194 CpuProfilesCollection* profiles);
195
196 // Called from events processing thread (Run() method.)
197 bool ProcessCodeEvent();
198
205
209 std::atomic_bool running_{true};
214 std::atomic<unsigned> last_code_event_id_;
217};
218
220 : public ProfilerEventsProcessor {
221 public:
222 SamplingEventsProcessor(Isolate* isolate, Symbolizer* symbolizer,
223 ProfilerCodeObserver* code_observer,
224 CpuProfilesCollection* profiles,
225 base::TimeDelta period, bool use_precise_sampling);
226 ~SamplingEventsProcessor() override;
227
228 // SamplingCircularQueue has stricter alignment requirements than a normal new
229 // can fulfil, so we need to provide our own new/delete here.
230 void* operator new(size_t size);
231 void operator delete(void* ptr);
232
233 void Run() override;
234
235 void SetSamplingInterval(base::TimeDelta period) override;
236
237 // Tick sample events are filled directly in the buffer of the circular
238 // queue (because the structure is of fixed width, but usually not all
239 // stack frame entries are filled.) This method returns a pointer to the
240 // next record of the buffer.
241 // These methods are not thread-safe and should only ever be called by one
242 // producer (from CpuSampler::SampleStack()). For testing, use AddSample.
243 inline TickSample* StartTickSample();
244 inline void FinishTickSample();
245
246 sampler::Sampler* sampler() { return sampler_.get(); }
247 base::TimeDelta period() const { return period_; }
248
249 private:
250 SampleProcessingResult ProcessOneSample() override;
251 void SymbolizeAndAddToProfiles(const TickSampleEventRecord* record);
252
253 static const size_t kTickSampleBufferSize = 512 * KB;
254 static const size_t kTickSampleQueueLength =
255 kTickSampleBufferSize / sizeof(TickSampleEventRecord);
257 kTickSampleQueueLength> ticks_buffer_;
258 std::unique_ptr<sampler::Sampler> sampler_;
259 base::TimeDelta period_; // Samples & code events processing period.
260 const bool use_precise_sampling_; // Whether or not busy-waiting is used for
261 // low sampling intervals on Windows.
262#if V8_OS_WIN
263 base::PreciseSleepTimer precise_sleep_timer_;
264#endif // V8_OS_WIN
265};
266
267// Builds and maintains an InstructionStreamMap tracking code objects on the VM
268// heap. While alive, logs generated code, callbacks, and builtins from the
269// isolate. Redirects events to the profiler events processor when present.
270// CodeEntry lifetime is associated with the given CodeEntryStorage.
272 public:
274
275 void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
276 CodeEntryStorage* code_entries() { return &code_entries_; }
278 WeakCodeRegistry* weak_code_registry() { return &weak_code_registry_; }
279 size_t GetEstimatedMemoryUsage() const;
280
281 void ClearCodeMap();
282
283 private:
285
286 void CodeEventHandlerInternal(const CodeEventsContainer& evt_rec);
287
288 void CreateEntriesForRuntimeCallStats();
289 void LogBuiltins();
290
292
293 // Redirects code events to be enqueued on the given events processor.
295 processor_ = processor;
296 }
297
298 // Stops redirection of code events onto an events processor.
299 void clear_processor() { processor_ = nullptr; }
300
306};
307
308// The CpuProfiler is a sampling CPU profiler for JS frames. It corresponds to
309// v8::CpuProfiler at the API level. It spawns an additional thread which is
310// responsible for triggering samples and then symbolizing the samples with
311// function names. To symbolize on a background thread, the profiler copies
312// metadata about generated code off-heap.
313//
314// Sampling is done using posix signals (except on Windows). The profiling
315// thread sends a signal to the main thread, based on a timer. The signal
316// handler can interrupt the main thread between any arbitrary instructions.
317// This means we are very careful about reading stack values during the signal
318// handler as we could be in the middle of an operation that is modifying the
319// stack.
320//
321// The story on Windows is similar except we use thread suspend and resume.
322//
323// Samples are passed to the profiling thread via a circular buffer. The
324// profiling thread symbolizes the samples by looking up the code pointers
325// against its own list of code objects. The profiling thread also listens for
326// code creation/move/deletion events (from the GC), to maintain its list of
327// code objects accurately.
329 public:
332
333 CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
334 CpuProfilingLoggingMode logging_mode,
335 CpuProfilesCollection* profiles, Symbolizer* test_symbolizer,
336 ProfilerEventsProcessor* test_processor,
337 ProfilerCodeObserver* test_code_observer);
338
339 ~CpuProfiler();
340 CpuProfiler(const CpuProfiler&) = delete;
342
343 static void CollectSample(Isolate* isolate,
344 std::optional<uint64_t> trace_id = std::nullopt);
345 static size_t GetAllProfilersMemorySize(Isolate* isolate);
346
352
353 base::TimeDelta sampling_interval() const { return base_sampling_interval_; }
354 void set_sampling_interval(base::TimeDelta value);
355 void set_use_precise_sampling(bool);
356 void CollectSample(const std::optional<uint64_t> trace_id = std::nullopt);
357 size_t GetEstimatedMemoryUsage() const;
358 CpuProfilingResult StartProfiling(
359 CpuProfilingOptions options = {},
360 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
361 CpuProfilingResult StartProfiling(
362 const char* title, CpuProfilingOptions options = {},
363 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
364 CpuProfilingResult StartProfiling(
365 Tagged<String> title, CpuProfilingOptions options = {},
366 std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
367
368 CpuProfile* StopProfiling(const char* title);
369 CpuProfile* StopProfiling(Tagged<String> title);
370 CpuProfile* StopProfiling(ProfilerId id);
371
372 int GetProfilesCount();
373 CpuProfile* GetProfile(int index);
374 void DeleteAllProfiles();
375 void DeleteProfile(CpuProfile* profile);
376
377 bool is_profiling() const { return is_profiling_; }
378
379 Symbolizer* symbolizer() const { return symbolizer_.get(); }
381 Isolate* isolate() const { return isolate_; }
382 CodeEntryStorage* code_entries() { return &code_entries_; }
383
385 return profiler_listener_.get();
386 }
388 return code_observer_->instruction_stream_map();
389 }
390
391 private:
392 void StartProcessorIfNotStarted();
393 void StopProcessor();
394 void ResetProfiles();
395
396 void EnableLogging();
397 void DisableLogging();
398
399 // Computes a sampling interval sufficient to accommodate attached profiles.
400 base::TimeDelta ComputeSamplingInterval();
401 // Dynamically updates the sampler to use a sampling interval sufficient for
402 // child profiles.
403 void AdjustSamplingInterval();
404
408 bool use_precise_sampling_ = true;
409 // Sampling interval to which per-profile sampling intervals will be clamped
410 // to a multiple of, or used as the default if unspecified.
412
413 // Storage for CodeEntry objects allocated by the profiler. May live for
414 // multiple profiling sessions, independent of heap listener state.
416
417 std::unique_ptr<ProfilerCodeObserver> code_observer_;
418 std::unique_ptr<CpuProfilesCollection> profiles_;
419 std::unique_ptr<Symbolizer> symbolizer_;
420 std::unique_ptr<ProfilerEventsProcessor> processor_;
421 std::unique_ptr<ProfilerListener> profiler_listener_;
422 std::unique_ptr<ProfilingScope> profiling_scope_;
424};
425
426} // namespace internal
427} // namespace v8
428
429#endif // V8_PROFILER_CPU_PROFILER_H_
Isolate * isolate_
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
CpuProfileDeoptFrame * deopt_frames
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
CodeEventsContainer(CodeEventRecord::Type type=CodeEventRecord::Type::kNoEvent)
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
ProfilerEventsProcessor * processor() const
Isolate * isolate() const
CpuProfiler & operator=(const CpuProfiler &)=delete
const NamingMode naming_mode_
ProfilerListener * profiler_listener_for_test() const
std::unique_ptr< CpuProfilesCollection > profiles_
Symbolizer * symbolizer() const
std::unique_ptr< ProfilerListener > profiler_listener_
CodeEntryStorage code_entries_
InstructionStreamMap * code_map_for_test()
std::unique_ptr< ProfilerCodeObserver > code_observer_
std::unique_ptr< Symbolizer > symbolizer_
CodeEntryStorage * code_entries()
std::unique_ptr< ProfilingScope > profiling_scope_
base::TimeDelta sampling_interval() const
base::TimeDelta base_sampling_interval_
CpuProfiler(const CpuProfiler &)=delete
std::unique_ptr< ProfilerEventsProcessor > processor_
const LoggingMode logging_mode_
WeakCodeRegistry * weak_code_registry()
ProfilerEventsProcessor * processor_
InstructionStreamMap * instruction_stream_map()
void set_processor(ProfilerEventsProcessor *processor)
CodeEntryStorage * code_entries()
ProfilerEventsProcessor * processor()
virtual void SetSamplingInterval(base::TimeDelta)
std::atomic< unsigned > last_code_event_id_
LockedQueue< CodeEventsContainer > events_buffer_
base::ConditionVariable running_cond_
virtual SampleProcessingResult ProcessOneSample()=0
LockedQueue< TickSampleEventRecord > ticks_from_vm_buffer_
ProfilerCodeObserver * code_observer_
CpuProfilesCollection * profiles_
ProfilerListener *const listener_
V8_INLINE void UpdateCodeMap(InstructionStreamMap *instruction_stream_map)
std::unique_ptr< sampler::Sampler > sampler_
SamplingCircularQueue< TickSampleEventRecord, kTickSampleQueueLength > ticks_buffer_
#define DECLARE_TYPE(type, value)
#define VM_EVENTS_TYPE_LIST(V)
#define DECLARE_CLASS(ignore, type)
DurationRecord record
ProcessorImpl * processor_
Definition mul-fft.cc:474
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation trace turbo cfg trace TurboFan s graph trimmer trace TurboFan s control equivalence trace TurboFan s register allocator trace stack load store counters for optimized code in run fuzzing &&concurrent_recompilation trace_turbo trace_turbo_scheduled trace_turbo_stack_accesses verify TurboFan machine graph of code stubs enable FixedArray bounds checks print TurboFan statistics of wasm compilations maximum cumulative size of bytecode considered for inlining scale factor of bytecode size used to calculate the inlining budget * KB
Definition flags.cc:1366
CpuProfilingStatus
CpuProfilingLoggingMode
@ kLazyLogging
CpuProfilingMode
CpuProfilingNamingMode
@ kDebugNaming
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500
#define V8_NODISCARD
Definition v8config.h:693
wasm::ValueType type