Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: runtime/vm/os_linux.cc

Issue 23437046: Add support for dumping code in jitdump file format (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« runtime/vm/code_observers.cc ('K') | « runtime/vm/code_observers.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" 5 #include "vm/globals.h"
6 #if defined(TARGET_OS_LINUX) 6 #if defined(TARGET_OS_LINUX)
7 7
8 #include "vm/os.h" 8 #include "vm/os.h"
9 9
10 #include <errno.h> // NOLINT 10 #include <errno.h> // NOLINT
11 #include <limits.h> // NOLINT 11 #include <limits.h> // NOLINT
12 #include <malloc.h> // NOLINT 12 #include <malloc.h> // NOLINT
13 #include <time.h> // NOLINT 13 #include <time.h> // NOLINT
14 #include <sys/resource.h> // NOLINT 14 #include <sys/resource.h> // NOLINT
15 #include <sys/time.h> // NOLINT 15 #include <sys/time.h> // NOLINT
16 #include <sys/types.h> // NOLINT 16 #include <sys/types.h> // NOLINT
17 #include <sys/syscall.h> // NOLINT
18 #include <sys/stat.h> // NOLINT
19 #include <fcntl.h> // NOLINT
17 #include <unistd.h> // NOLINT 20 #include <unistd.h> // NOLINT
18 21
19 #include "platform/utils.h" 22 #include "platform/utils.h"
20 #include "vm/code_observers.h" 23 #include "vm/code_observers.h"
21 #include "vm/dart.h" 24 #include "vm/dart.h"
22 #include "vm/debuginfo.h" 25 #include "vm/debuginfo.h"
23 #include "vm/isolate.h" 26 #include "vm/isolate.h"
27 #include "vm/thread.h"
24 #include "vm/vtune.h" 28 #include "vm/vtune.h"
25 #include "vm/zone.h" 29 #include "vm/zone.h"
26 30
27 31
28 namespace dart { 32 namespace dart {
29 33
30 // Linux CodeObservers. 34 // Linux CodeObservers.
31 35
32 DEFINE_FLAG(bool, generate_gdb_symbols, false, 36 DEFINE_FLAG(bool, generate_gdb_symbols, false,
33 "Generate symbols of generated dart functions for debugging with GDB"); 37 "Generate symbols of generated dart functions for debugging with GDB");
34 DEFINE_FLAG(bool, generate_perf_events_symbols, false, 38 DEFINE_FLAG(bool, generate_perf_events_symbols, false,
35 "Generate events symbols for profiling with perf"); 39 "Generate events symbols for profiling with perf");
36 DEFINE_FLAG(bool, ll_prof, false, 40 DEFINE_FLAG(bool, ll_prof, false,
37 "Generate compiled code log file for processing with ll_prof.py."); 41 "Generate compiled code log file for processing with ll_prof.py.");
38 DEFINE_FLAG(charp, generate_pprof_symbols, NULL, 42 DEFINE_FLAG(charp, generate_pprof_symbols, NULL,
39 "Writes pprof events symbols to the provided file"); 43 "Writes pprof events symbols to the provided file");
44 DEFINE_FLAG(bool, generate_perf_jitdump, true,
45 "Writes jitdump data for profiling with perf annotate");
40 46
41 class LowLevelProfileCodeObserver : public CodeObserver { 47 class LowLevelProfileCodeObserver : public CodeObserver {
42 public: 48 public:
43 LowLevelProfileCodeObserver() { 49 LowLevelProfileCodeObserver() {
44 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); 50 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
45 if (file_open == NULL) { 51 if (file_open == NULL) {
46 return; 52 return;
47 } 53 }
48 const char* filename = "v8.log.ll"; 54 const char* filename = "v8.log.ll";
49 log_file_ = (*file_open)(filename, true); 55 log_file_ = (*file_open)(filename, true);
50 #if defined(TARGET_ARCH_IA32) 56 #if defined(TARGET_ARCH_IA32)
51 const char arch[] = "ia32"; 57 const char arch[] = "ia32";
52 #elif defined(TARGET_ARCH_X64) 58 #elif defined(TARGET_ARCH_X64)
53 const char arch[] = "x64"; 59 const char arch[] = "x64";
54 #elif defined(TARGET_ARCH_ARM) 60 #elif defined(TARGET_ARCH_ARM)
55 const char arch[] = "arm"; 61 const char arch[] = "arm";
56 #elif defined(TARGET_ARCH_MIPS) 62 #elif defined(TARGET_ARCH_MIPS)
57 const char arch[] = "mips"; 63 const char arch[] = "mips";
58 #else 64 #else
59 const char arch[] = "unknown"; 65 #error Unknown architecture.
60 #endif 66 #endif
61 LowLevelLogWriteBytes(arch, sizeof(arch)); 67 LowLevelLogWriteBytes(arch, sizeof(arch));
62 } 68 }
63 69
64 ~LowLevelProfileCodeObserver() { 70 ~LowLevelProfileCodeObserver() {
65 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); 71 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
66 if (file_close == NULL) { 72 if (file_close == NULL) {
67 return; 73 return;
68 } 74 }
69 ASSERT(log_file_ != NULL); 75 ASSERT(log_file_ != NULL);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 const char* marker = optimized ? "*" : ""; 109 const char* marker = optimized ? "*" : "";
104 char* name_buffer = 110 char* name_buffer =
105 Isolate::Current()->current_zone()->PrintToString("%s%s", marker, name); 111 Isolate::Current()->current_zone()->PrintToString("%s%s", marker, name);
106 intptr_t len = strlen(name_buffer); 112 intptr_t len = strlen(name_buffer);
107 113
108 LowLevelCodeCreateStruct event; 114 LowLevelCodeCreateStruct event;
109 event.name_size = len; 115 event.name_size = len;
110 event.code_address = base; 116 event.code_address = base;
111 event.code_size = size; 117 event.code_size = size;
112 118
113 LowLevelLogWriteStruct(event); 119 {
114 LowLevelLogWriteBytes(name_buffer, len); 120 MutexLocker ml(CodeObservers::mutex());
115 LowLevelLogWriteBytes(reinterpret_cast<char*>(base), size); 121 LowLevelLogWriteStruct(event);
122 LowLevelLogWriteBytes(name_buffer, len);
123 LowLevelLogWriteBytes(reinterpret_cast<char*>(base), size);
124 }
116 } 125 }
117 126
118 private: 127 private:
119 void* log_file_; 128 void* log_file_;
120 129
121 DISALLOW_COPY_AND_ASSIGN(LowLevelProfileCodeObserver); 130 DISALLOW_COPY_AND_ASSIGN(LowLevelProfileCodeObserver);
122 }; 131 };
123 132
124 133
125 class PerfCodeObserver : public CodeObserver { 134 class PerfCodeObserver : public CodeObserver {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 uword size, 166 uword size,
158 bool optimized) { 167 bool optimized) {
159 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); 168 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
160 ASSERT(file_write != NULL); 169 ASSERT(file_write != NULL);
161 const char* format = "%" Px " %" Px " %s%s\n"; 170 const char* format = "%" Px " %" Px " %s%s\n";
162 const char* marker = optimized ? "*" : ""; 171 const char* marker = optimized ? "*" : "";
163 intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name); 172 intptr_t len = OS::SNPrint(NULL, 0, format, base, size, marker, name);
164 char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1); 173 char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
165 OS::SNPrint(buffer, len + 1, format, base, size, marker, name); 174 OS::SNPrint(buffer, len + 1, format, base, size, marker, name);
166 ASSERT(out_file_ != NULL); 175 ASSERT(out_file_ != NULL);
167 (*file_write)(buffer, len, out_file_); 176 {
177 MutexLocker ml(CodeObservers::mutex());
178 (*file_write)(buffer, len, out_file_);
179 }
168 } 180 }
169 181
170 private: 182 private:
171 void* out_file_; 183 void* out_file_;
172 184
173 DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver); 185 DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
174 }; 186 };
175 187
176 class PprofCodeObserver : public CodeObserver { 188 class PprofCodeObserver : public CodeObserver {
177 public: 189 public:
(...skipping 19 matching lines...) Expand all
197 } 209 }
198 const char* filename = FLAG_generate_pprof_symbols; 210 const char* filename = FLAG_generate_pprof_symbols;
199 void* out_file = (*file_open)(filename, true); 211 void* out_file = (*file_open)(filename, true);
200 ASSERT(out_file != NULL); 212 ASSERT(out_file != NULL);
201 DebugInfo::ByteBuffer* debug_region = new DebugInfo::ByteBuffer(); 213 DebugInfo::ByteBuffer* debug_region = new DebugInfo::ByteBuffer();
202 ASSERT(debug_region != NULL); 214 ASSERT(debug_region != NULL);
203 pprof_symbol_generator_->WriteToMemory(debug_region); 215 pprof_symbol_generator_->WriteToMemory(debug_region);
204 int buffer_size = debug_region->size(); 216 int buffer_size = debug_region->size();
205 void* buffer = debug_region->data(); 217 void* buffer = debug_region->data();
206 if (buffer_size > 0) { 218 if (buffer_size > 0) {
219 MutexLocker ml(CodeObservers::mutex());
207 ASSERT(buffer != NULL); 220 ASSERT(buffer != NULL);
208 (*file_write)(buffer, buffer_size, out_file); 221 (*file_write)(buffer, buffer_size, out_file);
209 } 222 }
210 delete debug_region; 223 delete debug_region;
211 (*file_close)(out_file); 224 (*file_close)(out_file);
212 DebugInfo::UnregisterAllSections(); 225 DebugInfo::UnregisterAllSections();
213 } 226 }
214 227
215 virtual bool IsActive() const { 228 virtual bool IsActive() const {
216 return FLAG_generate_pprof_symbols != NULL; 229 return FLAG_generate_pprof_symbols != NULL;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } else { 275 } else {
263 DebugInfo::RegisterSection(name, base, size); 276 DebugInfo::RegisterSection(name, base, size);
264 } 277 }
265 } 278 }
266 279
267 private: 280 private:
268 DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver); 281 DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver);
269 }; 282 };
270 283
271 284
285 #define CLOCKFD 3
286 #define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) // NOLINT
287
288 class JitdumpCodeObserver : public CodeObserver {
289 public:
290 JitdumpCodeObserver() {
291 ASSERT(FLAG_generate_perf_jitdump);
292 out_file_ = NULL;
293 clock_fd_ = -1;
294 clock_id_ = kInvalidClockId;
295 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
296 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
297 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
298 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
299 return;
300 }
301 // The Jitdump code observer writes all jitted code into
302 // /tmp/jit-<pid>.dump, we open the file once on initialization and close
303 // it when the VM is going down.
304 {
305 // Open the file.
306 const char* format = "/tmp/jit-%ld.dump";
Ivan Posva 2014/02/25 08:09:04 We have the macro Pd for intptr_t sized %d formats
Cutch 2014/02/26 22:28:28 Done.
307 intptr_t pid = getpid();
308 intptr_t len = OS::SNPrint(NULL, 0, format, pid);
309 char* filename = new char[len + 1];
310 OS::SNPrint(filename, len + 1, format, pid);
311 out_file_ = (*file_open)(filename, true);
312 ASSERT(out_file_ != NULL);
313 // Write the jit dump header.
314 WriteHeader();
315 }
316 // perf uses an internal clock and because our output is merged with data
317 // collected by perf our timestamps must be consistent. Using
318 // the posix-clock-module (/dev/trace_clock) as our time source ensures
319 // we are consistent with the perf timestamps.
320 clock_id_ = kInvalidClockId;
321 clock_fd_ = open("/dev/trace_clock", O_RDONLY);
322 if (clock_fd_ >= 0) {
323 clock_id_ = FD_TO_CLOCKID(clock_fd_);
324 }
325 }
326
327 ~JitdumpCodeObserver() {
328 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
329 if (file_close == NULL) {
330 return;
331 }
332 ASSERT(out_file_ != NULL);
333 (*file_close)(out_file_);
334 if (clock_fd_ >= 0) {
335 close(clock_fd_);
336 }
337 }
338
339 virtual bool IsActive() const {
340 return FLAG_generate_perf_jitdump && (out_file_ != NULL);
341 }
342
343 virtual void Notify(const char* name,
344 uword base,
345 uword prologue_offset,
346 uword size,
347 bool optimized) {
348 WriteCodeLoad(name, base, prologue_offset, size, optimized);
349 }
350
351 private:
352 static const uint32_t kJitHeaderMagic = 0x4F74496A;
353 static const uint32_t kJitHeaderVersion = 0x2;
354 static const uint32_t kElfMachIA32 = 3;
355 static const uint32_t kElfMachX64 = 62;
356 static const uint32_t kElfMachARM = 40;
357 static const uint32_t kElfMachMIPS = 10;
358 static const int kInvalidClockId = -1;
359
360 struct jitheader {
361 uint32_t magic;
362 uint32_t version;
363 uint32_t total_size;
364 uint32_t elf_mach;
365 uint32_t pad1;
366 uint32_t pid;
367 uint64_t timestamp;
368 };
369
370 enum jit_record_type {
371 JIT_CODE_LOAD = 0,
372 /* JIT_CODE_UNLOAD = 1, */
373 /* JIT_CODE_CLOSE = 2, */
374 /* JIT_CODE_DEBUG_INFO = 3, */
375 JIT_CODE_MAX = 4,
376 };
377
378 struct jr_code_load {
379 uint32_t id;
380 uint32_t total_size;
381 uint64_t timestamp;
382 uint32_t pid;
383 uint32_t tid;
384 uint64_t vma;
385 uint64_t code_addr;
386 uint32_t code_size;
387 uint32_t align;
388 };
389
390 const char* GenerateCodeName(const char* name, bool optimized) {
391 const char* format = "%s%s";
392 const char* marker = optimized ? "*" : "";
393 intptr_t len = OS::SNPrint(NULL, 0, format, marker, name);
394 char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
395 OS::SNPrint(buffer, len + 1, format, marker, name);
396 return buffer;
397 }
398
399 uint32_t GetElfMach() {
400 #if defined(TARGET_ARCH_IA32)
401 return kElfMachIA32;
402 #elif defined(TARGET_ARCH_X64)
403 return kElfMachX64;
404 #elif defined(TARGET_ARCH_ARM)
405 return kElfMachARM;
406 #elif defined(TARGET_ARCH_MIPS)
407 return kElfMachMIPS;
408 #else
409 #error Unknown architecture.
410 #endif
411 }
412
413 pid_t gettid() {
414 // libc does wrap the Linux-specific gettid system call.
Ivan Posva 2014/02/25 08:09:04 does or doesn't?
Cutch 2014/02/26 22:28:28 Done.
415 // Note that this thread id is not the same as the posix thread id.
416 return syscall(SYS_gettid);
417 }
418
419 uint64_t GetKernelTimeNanos() {
420 if (clock_id_ != kInvalidClockId) {
421 struct timespec ts;
422 int r = clock_gettime(clock_id_, &ts);
423 ASSERT(r == 0);
424 uint64_t nanos = static_cast<uint64_t>(ts.tv_sec) *
425 static_cast<uint64_t>(kNanosecondsPerSecond);
426 nanos += static_cast<uint64_t>(ts.tv_nsec);
427 return nanos;
428 } else {
429 return OS::GetCurrentTimeMicros() * kNanosecondsPerMicrosecond;
430 }
431 }
432
433 void WriteHeader() {
434 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
435 ASSERT(file_write != NULL);
436 ASSERT(out_file_ != NULL);
437 jitheader header;
438 header.magic = kJitHeaderMagic;
439 header.version = kJitHeaderVersion;
440 header.total_size = sizeof(jitheader);
441 header.pad1 = 0xdeadbeef;
442 header.elf_mach = GetElfMach();
443 header.pid = getpid();
444 header.timestamp = GetKernelTimeNanos();
445 {
446 MutexLocker ml(CodeObservers::mutex());
447 (*file_write)(&header, sizeof(header), out_file_);
448 }
449 }
450
451 void WriteCodeLoad(const char* name, uword base, uword prologue_offset,
452 uword code_size, bool optimized) {
453 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
454 ASSERT(file_write != NULL);
455 ASSERT(out_file_ != NULL);
456
457 const char* code_name = GenerateCodeName(name, optimized);
458 const intptr_t code_name_size = strlen(code_name) + 1;
459 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(base);
460
461 jr_code_load code_load;
462 code_load.id = JIT_CODE_LOAD;
463 code_load.total_size = sizeof(code_load) + code_name_size + code_size;
464 code_load.timestamp = GetKernelTimeNanos();
465 code_load.pid = getpid();
466 code_load.tid = gettid();
467 code_load.vma = 0x0; // Our addresses are absolute.
468 code_load.code_addr = base;
469 code_load.code_size = code_size;
470 code_load.align = OS::PreferredCodeAlignment();
471
472 {
473 MutexLocker ml(CodeObservers::mutex());
474 (*file_write)(&code_load, sizeof(code_load), out_file_);
475 (*file_write)(code_name, code_name_size, out_file_);
476 (*file_write)(code_pointer, code_size, out_file_);
477 }
478 }
479
480 void* out_file_;
481 int clock_fd_;
482 int clock_id_;
483 DISALLOW_COPY_AND_ASSIGN(JitdumpCodeObserver);
484 };
485
486
272 const char* OS::Name() { 487 const char* OS::Name() {
273 return "linux"; 488 return "linux";
274 } 489 }
275 490
276 491
277 intptr_t OS::ProcessId() { 492 intptr_t OS::ProcessId() {
278 return static_cast<intptr_t>(getpid()); 493 return static_cast<intptr_t>(getpid());
279 } 494 }
280 495
281 496
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 } 720 }
506 if (FLAG_generate_perf_events_symbols) { 721 if (FLAG_generate_perf_events_symbols) {
507 CodeObservers::Register(new PerfCodeObserver); 722 CodeObservers::Register(new PerfCodeObserver);
508 } 723 }
509 if (FLAG_generate_gdb_symbols) { 724 if (FLAG_generate_gdb_symbols) {
510 CodeObservers::Register(new GdbCodeObserver); 725 CodeObservers::Register(new GdbCodeObserver);
511 } 726 }
512 if (FLAG_generate_pprof_symbols != NULL) { 727 if (FLAG_generate_pprof_symbols != NULL) {
513 CodeObservers::Register(new PprofCodeObserver); 728 CodeObservers::Register(new PprofCodeObserver);
514 } 729 }
730 if (FLAG_generate_perf_jitdump) {
731 CodeObservers::Register(new JitdumpCodeObserver);
732 }
515 #if defined(DART_VTUNE_SUPPORT) 733 #if defined(DART_VTUNE_SUPPORT)
516 CodeObservers::Register(new VTuneCodeObserver); 734 CodeObservers::Register(new VTuneCodeObserver);
517 #endif 735 #endif
518 } 736 }
519 737
520 738
521 void OS::PrintErr(const char* format, ...) { 739 void OS::PrintErr(const char* format, ...) {
522 va_list args; 740 va_list args;
523 va_start(args, format); 741 va_start(args, format);
524 VFPrint(stderr, format, args); 742 VFPrint(stderr, format, args);
(...skipping 20 matching lines...) Expand all
545 } 763 }
546 764
547 765
548 void OS::Exit(int code) { 766 void OS::Exit(int code) {
549 exit(code); 767 exit(code);
550 } 768 }
551 769
552 } // namespace dart 770 } // namespace dart
553 771
554 #endif // defined(TARGET_OS_LINUX) 772 #endif // defined(TARGET_OS_LINUX)
OLDNEW
« runtime/vm/code_observers.cc ('K') | « runtime/vm/code_observers.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698