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_LOG_H_
6 #define V8_LOG_H_
7
8 #include <string>
9
10 #include "src/allocation.h"
11 #include "src/base/compiler-specific.h"
12 #include "src/base/platform/elapsed-timer.h"
13 #include "src/base/platform/platform.h"
14 #include "src/code-events.h"
15 #include "src/isolate.h"
16 #include "src/objects.h"
17
18 namespace v8 {
19
20 namespace base {
21 class Semaphore;
22 }
23
24 namespace sampler {
25 class Sampler;
26 }
27
28 namespace internal {
29
30 // Logger is used for collecting logging information from V8 during
31 // execution. The result is dumped to a file.
32 //
33 // Available command line flags:
34 //
35 // --log
36 // Minimal logging (no API, code, or GC sample events), default is off.
37 //
38 // --log-all
39 // Log all events to the file, default is off. This is the same as combining
40 // --log-api, --log-code, --log-gc, and --log-regexp.
41 //
42 // --log-api
43 // Log API events to the logfile, default is off. --log-api implies --log.
44 //
45 // --log-code
46 // Log code (create, move, and delete) events to the logfile, default is off.
47 // --log-code implies --log.
48 //
49 // --log-gc
50 // Log GC heap samples after each GC that can be processed by hp2ps, default
51 // is off. --log-gc implies --log.
52 //
53 // --log-regexp
54 // Log creation and use of regular expressions, Default is off.
55 // --log-regexp implies --log.
56 //
57 // --logfile <filename>
58 // Specify the name of the logfile, default is "v8.log".
59 //
60 // --prof
61 // Collect statistical profiling information (ticks), default is off. The
62 // tick profiler requires code events, so --prof implies --log-code.
63
64 // Forward declarations.
65 class CodeEventListener;
66 class CpuProfiler;
67 class Isolate;
68 class Log;
69 class PositionsRecorder;
70 class Profiler;
71 class Ticker;
72 struct TickSample;
73 class RuntimeCallTimer;
74
75 #undef LOG
76 #define LOG(isolate, Call) \
77 do { \
78 v8::internal::Logger* logger = (isolate)->logger(); \
79 if (logger->is_logging()) logger->Call; \
80 } while (false)
81
82 #define LOG_CODE_EVENT(isolate, Call) \
83 do { \
84 v8::internal::Logger* logger = (isolate)->logger(); \
85 if (logger->is_logging_code_events()) logger->Call; \
86 } while (false)
87
88 class JitLogger;
89 class PerfBasicLogger;
90 class LowLevelLogger;
91 class PerfJitLogger;
92 class ProfilerListener;
93
94 class Logger : public CodeEventListener {
95 public:
96 enum StartEnd { START = 0, END = 1 };
97
98 // Acquires resources for logging if the right flags are set.
99 bool SetUp(Isolate* isolate);
100
101 // Sets the current code event handler.
102 void SetCodeEventHandler(uint32_t options,
103 JitCodeEventHandler event_handler);
104
105 // Sets up ProfilerListener.
106 void SetUpProfilerListener();
107
108 // Tear down ProfilerListener if it has no observers.
109 void TearDownProfilerListener();
110
111 sampler::Sampler* sampler();
112
profiler_listener()113 ProfilerListener* profiler_listener() { return profiler_listener_.get(); }
114
115 // Frees resources acquired in SetUp.
116 // When a temporary file is used for the log, returns its stream descriptor,
117 // leaving the file open.
118 FILE* TearDown();
119
120 // Emits an event with a string value -> (name, value).
121 void StringEvent(const char* name, const char* value);
122
123 // Emits an event with an int value -> (name, value).
124 void IntEvent(const char* name, int value);
125 void IntPtrTEvent(const char* name, intptr_t value);
126
127 // Emits an event with an handle value -> (name, location).
128 void HandleEvent(const char* name, Object** location);
129
130 // Emits memory management events for C allocated structures.
131 void NewEvent(const char* name, void* object, size_t size);
132 void DeleteEvent(const char* name, void* object);
133
134 // Emits an event with a tag, and some resource usage information.
135 // -> (name, tag, <rusage information>).
136 // Currently, the resource usage information is a process time stamp
137 // and a real time timestamp.
138 void ResourceEvent(const char* name, const char* tag);
139
140 // Emits an event that an undefined property was read from an
141 // object.
142 void SuspectReadEvent(Name* name, Object* obj);
143
144 // Emits an event when a message is put on or read from a debugging queue.
145 // DebugTag lets us put a call-site specific label on the event.
146 void DebugTag(const char* call_site_tag);
147 void DebugEvent(const char* event_type, Vector<uint16_t> parameter);
148
149
150 // ==== Events logged by --log-api. ====
151 void ApiSecurityCheck();
152 void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
153 void ApiIndexedPropertyAccess(const char* tag,
154 JSObject* holder,
155 uint32_t index);
156 void ApiObjectAccess(const char* tag, JSObject* obj);
157 void ApiEntryCall(const char* name);
158
159 // ==== Events logged by --log-code. ====
160 void addCodeEventListener(CodeEventListener* listener);
161 void removeCodeEventListener(CodeEventListener* listener);
162
163 // Emits a code event for a callback function.
164 void CallbackEvent(Name* name, Address entry_point);
165 void GetterCallbackEvent(Name* name, Address entry_point);
166 void SetterCallbackEvent(Name* name, Address entry_point);
167 // Emits a code create event.
168 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
169 AbstractCode* code, const char* source);
170 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
171 AbstractCode* code, Name* name);
172 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
173 AbstractCode* code, SharedFunctionInfo* shared,
174 Name* name);
175 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
176 AbstractCode* code, SharedFunctionInfo* shared,
177 Name* source, int line, int column);
178 void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
179 AbstractCode* code, int args_count);
180 // Emits a code deoptimization event.
181 void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared);
182 void CodeMovingGCEvent();
183 // Emits a code create event for a RegExp.
184 void RegExpCodeCreateEvent(AbstractCode* code, String* source);
185 // Emits a code move event.
186 void CodeMoveEvent(AbstractCode* from, Address to);
187 // Emits a code line info add event with Postion type.
188 void CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
189 int pc_offset,
190 int position);
191 // Emits a code line info add event with StatementPostion type.
192 void CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
193 int pc_offset,
194 int position);
195 // Emits a code line info start to record event
196 void CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder);
197 // Emits a code line info finish record event.
198 // It's the callee's responsibility to dispose the parameter jit_handler_data.
199 void CodeEndLinePosInfoRecordEvent(AbstractCode* code,
200 void* jit_handler_data);
201
202 void SharedFunctionInfoMoveEvent(Address from, Address to);
203
204 void CodeNameEvent(Address addr, int pos, const char* code_name);
205
206 void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
207
208 // ==== Events logged by --log-gc. ====
209 // Heap sampling events: start, end, and individual types.
210 void HeapSampleBeginEvent(const char* space, const char* kind);
211 void HeapSampleEndEvent(const char* space, const char* kind);
212 void HeapSampleItemEvent(const char* type, int number, int bytes);
213 void HeapSampleJSConstructorEvent(const char* constructor,
214 int number, int bytes);
215 void HeapSampleJSRetainersEvent(const char* constructor,
216 const char* event);
217 void HeapSampleJSProducerEvent(const char* constructor,
218 Address* stack);
219 void HeapSampleStats(const char* space, const char* kind,
220 intptr_t capacity, intptr_t used);
221
222 void SharedLibraryEvent(const std::string& library_path, uintptr_t start,
223 uintptr_t end, intptr_t aslr_slide);
224
225 void CurrentTimeEvent();
226
227 void TimerEvent(StartEnd se, const char* name);
228
229 static void EnterExternal(Isolate* isolate);
230 static void LeaveExternal(Isolate* isolate);
231
DefaultEventLoggerSentinel(const char * name,int event)232 static void DefaultEventLoggerSentinel(const char* name, int event) {}
233
234 INLINE(static void CallEventLogger(Isolate* isolate, const char* name,
235 StartEnd se, bool expose_to_api));
236
237 // ==== Events logged by --log-regexp ====
238 // Regexp compilation and execution events.
239
240 void RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache);
241
is_logging()242 bool is_logging() {
243 return is_logging_;
244 }
245
is_logging_code_events()246 bool is_logging_code_events() {
247 return is_logging() || jit_logger_ != NULL;
248 }
249
250 // Stop collection of profiling data.
251 // When data collection is paused, CPU Tick events are discarded.
252 void StopProfiler();
253
254 void LogExistingFunction(Handle<SharedFunctionInfo> shared,
255 Handle<AbstractCode> code);
256 // Logs all compiled functions found in the heap.
257 void LogCompiledFunctions();
258 // Logs all accessor callbacks found in the heap.
259 void LogAccessorCallbacks();
260 // Used for logging stubs found in the snapshot.
261 void LogCodeObjects();
262 // Used for logging bytecode handlers found in the snapshot.
263 void LogBytecodeHandlers();
264
265 // Converts tag to a corresponding NATIVE_... if the script is native.
266 INLINE(static CodeEventListener::LogEventsAndTags ToNativeByScript(
267 CodeEventListener::LogEventsAndTags, Script*));
268
269 // Profiler's sampling interval (in milliseconds).
270 #if defined(ANDROID)
271 // Phones and tablets have processors that are much slower than desktop
272 // and laptop computers for which current heuristics are tuned.
273 static const int kSamplingIntervalMs = 5;
274 #else
275 static const int kSamplingIntervalMs = 1;
276 #endif
277
278 // Callback from Log, stops profiling in case of insufficient resources.
279 void LogFailure();
280
281 private:
282 explicit Logger(Isolate* isolate);
283 ~Logger();
284
285 // Emits the profiler's first message.
286 void ProfilerBeginEvent();
287
288 // Emits callback event messages.
289 void CallbackEventInternal(const char* prefix,
290 Name* name,
291 Address entry_point);
292
293 // Internal configurable move event.
294 void MoveEventInternal(CodeEventListener::LogEventsAndTags event,
295 Address from, Address to);
296
297 // Used for logging stubs found in the snapshot.
298 void LogCodeObject(Object* code_object);
299
300 // Helper method. It resets name_buffer_ and add tag name into it.
301 void InitNameBuffer(CodeEventListener::LogEventsAndTags tag);
302
303 // Emits a profiler tick event. Used by the profiler thread.
304 void TickEvent(TickSample* sample, bool overflow);
305 void RuntimeCallTimerEvent();
306
307 PRINTF_FORMAT(2, 3) void ApiEvent(const char* format, ...);
308
309 // Logs a StringEvent regardless of whether FLAG_log is true.
310 void UncheckedStringEvent(const char* name, const char* value);
311
312 // Logs an IntEvent regardless of whether FLAG_log is true.
313 void UncheckedIntEvent(const char* name, int value);
314 void UncheckedIntPtrTEvent(const char* name, intptr_t value);
315
316 Isolate* isolate_;
317
318 // The sampler used by the profiler and the sliding state window.
319 Ticker* ticker_;
320
321 // When the statistical profile is active, profiler_
322 // points to a Profiler, that handles collection
323 // of samples.
324 Profiler* profiler_;
325
326 // An array of log events names.
327 const char* const* log_events_;
328
329 // Internal implementation classes with access to
330 // private members.
331 friend class EventLog;
332 friend class Isolate;
333 friend class TimeLog;
334 friend class Profiler;
335 template <StateTag Tag> friend class VMState;
336 friend class LoggerTestHelper;
337
338 bool is_logging_;
339 Log* log_;
340 PerfBasicLogger* perf_basic_logger_;
341 PerfJitLogger* perf_jit_logger_;
342 LowLevelLogger* ll_logger_;
343 JitLogger* jit_logger_;
344 std::unique_ptr<ProfilerListener> profiler_listener_;
345 List<CodeEventListener*> listeners_;
346
347 // Guards against multiple calls to TearDown() that can happen in some tests.
348 // 'true' between SetUp() and TearDown().
349 bool is_initialized_;
350
351 base::ElapsedTimer timer_;
352
353 friend class CpuProfiler;
354 };
355
356 #define TIMER_EVENTS_LIST(V) \
357 V(RecompileSynchronous, true) \
358 V(RecompileConcurrent, true) \
359 V(CompileIgnition, true) \
360 V(CompileFullCode, true) \
361 V(OptimizeCode, true) \
362 V(CompileCode, true) \
363 V(DeoptimizeCode, true) \
364 V(Execute, true) \
365 V(External, true) \
366 V(IcMiss, false)
367
368 #define V(TimerName, expose) \
369 class TimerEvent##TimerName : public AllStatic { \
370 public: \
371 static const char* name(void* unused = NULL) { return "V8." #TimerName; } \
372 static bool expose_to_api() { return expose; } \
373 };
TIMER_EVENTS_LIST(V)374 TIMER_EVENTS_LIST(V)
375 #undef V
376
377
378 template <class TimerEvent>
379 class TimerEventScope {
380 public:
381 explicit TimerEventScope(Isolate* isolate) : isolate_(isolate) {
382 LogTimerEvent(Logger::START);
383 }
384
385 ~TimerEventScope() { LogTimerEvent(Logger::END); }
386
387 void LogTimerEvent(Logger::StartEnd se);
388
389 private:
390 Isolate* isolate_;
391 };
392
393 class PositionsRecorder BASE_EMBEDDED {
394 public:
PositionsRecorder()395 PositionsRecorder() { jit_handler_data_ = NULL; }
396
AttachJITHandlerData(void * user_data)397 void AttachJITHandlerData(void* user_data) { jit_handler_data_ = user_data; }
398
DetachJITHandlerData()399 void* DetachJITHandlerData() {
400 void* old_data = jit_handler_data_;
401 jit_handler_data_ = NULL;
402 return old_data;
403 }
404
405 protected:
406 // Currently jit_handler_data_ is used to store JITHandler-specific data
407 // over the lifetime of a PositionsRecorder
408 void* jit_handler_data_;
409
410 private:
411 DISALLOW_COPY_AND_ASSIGN(PositionsRecorder);
412 };
413
414 class CodeEventLogger : public CodeEventListener {
415 public:
416 CodeEventLogger();
417 ~CodeEventLogger() override;
418
419 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
420 const char* comment) override;
421 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
422 Name* name) override;
423 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
424 int args_count) override;
425 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
426 SharedFunctionInfo* shared, Name* name) override;
427 void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
428 SharedFunctionInfo* shared, Name* source, int line,
429 int column) override;
430 void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
431
CallbackEvent(Name * name,Address entry_point)432 void CallbackEvent(Name* name, Address entry_point) override {}
GetterCallbackEvent(Name * name,Address entry_point)433 void GetterCallbackEvent(Name* name, Address entry_point) override {}
SetterCallbackEvent(Name * name,Address entry_point)434 void SetterCallbackEvent(Name* name, Address entry_point) override {}
SharedFunctionInfoMoveEvent(Address from,Address to)435 void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
CodeMovingGCEvent()436 void CodeMovingGCEvent() override {}
CodeDeoptEvent(Code * code,Address pc,int fp_to_sp_delta)437 void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override {}
438
439 private:
440 class NameBuffer;
441
442 virtual void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo* shared,
443 const char* name, int length) = 0;
444
445 NameBuffer* name_buffer_;
446 };
447
448
449 } // namespace internal
450 } // namespace v8
451
452
453 #endif // V8_LOG_H_
454