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

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, 9 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
« no previous file with comments | « 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 code_sequence_ = 0;
296 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
297 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
298 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
299 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
300 return;
301 }
302 // The Jitdump code observer writes all jitted code into
303 // /tmp/jit-<pid>.dump, we open the file once on initialization and close
304 // it when the VM is going down.
305 {
306 // Open the file.
307 const char* format = "/tmp/jit-%" Pd ".dump";
308 intptr_t pid = getpid();
309 intptr_t len = OS::SNPrint(NULL, 0, format, pid);
310 char* filename = new char[len + 1];
311 OS::SNPrint(filename, len + 1, format, pid);
312 out_file_ = (*file_open)(filename, true);
313 ASSERT(out_file_ != NULL);
314 // Write the jit dump header.
315 WriteHeader();
316 }
317 // perf uses an internal clock and because our output is merged with data
318 // collected by perf our timestamps must be consistent. Using
319 // the posix-clock-module (/dev/trace_clock) as our time source ensures
320 // we are consistent with the perf timestamps.
321 clock_id_ = kInvalidClockId;
322 clock_fd_ = open("/dev/trace_clock", O_RDONLY);
323 if (clock_fd_ >= 0) {
324 clock_id_ = FD_TO_CLOCKID(clock_fd_);
325 }
326 }
327
328 ~JitdumpCodeObserver() {
329 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
330 if (file_close == NULL) {
331 return;
332 }
333 ASSERT(out_file_ != NULL);
334 (*file_close)(out_file_);
335 if (clock_fd_ >= 0) {
336 close(clock_fd_);
337 }
338 }
339
340 virtual bool IsActive() const {
341 return FLAG_generate_perf_jitdump && (out_file_ != NULL);
342 }
343
344 virtual void Notify(const char* name,
345 uword base,
346 uword prologue_offset,
347 uword size,
348 bool optimized) {
349 WriteCodeLoad(name, base, prologue_offset, size, optimized);
350 }
351
352 private:
353 static const uint32_t kJitHeaderMagic = 0x4F74496A;
354 static const uint32_t kJitHeaderVersion = 0x2;
355 static const uint32_t kElfMachIA32 = 3;
356 static const uint32_t kElfMachX64 = 62;
357 static const uint32_t kElfMachARM = 40;
358 static const uint32_t kElfMachMIPS = 10;
359 static const int kInvalidClockId = -1;
360
361 struct jitheader {
362 uint32_t magic;
363 uint32_t version;
364 uint32_t total_size;
365 uint32_t elf_mach;
366 uint32_t pad1;
367 uint32_t pid;
368 uint64_t timestamp;
369 };
370
371 enum jit_record_type {
372 JIT_CODE_LOAD = 0,
373 /* JIT_CODE_UNLOAD = 1, */
374 /* JIT_CODE_CLOSE = 2, */
375 /* JIT_CODE_DEBUG_INFO = 3, */
376 JIT_CODE_MAX = 4,
377 };
378
379 struct jr_code_load {
380 uint32_t id;
381 uint32_t total_size;
382 uint64_t timestamp;
383 uint32_t pid;
384 uint32_t tid;
385 uint64_t vma;
386 uint64_t code_addr;
387 uint32_t code_size;
388 uint64_t code_index;
389 uint32_t align;
390 };
391
392 const char* GenerateCodeName(const char* name, bool optimized) {
393 const char* format = "%s%s";
394 const char* marker = optimized ? "*" : "";
395 intptr_t len = OS::SNPrint(NULL, 0, format, marker, name);
396 char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
397 OS::SNPrint(buffer, len + 1, format, marker, name);
398 return buffer;
399 }
400
401 uint32_t GetElfMach() {
402 #if defined(TARGET_ARCH_IA32)
403 return kElfMachIA32;
404 #elif defined(TARGET_ARCH_X64)
405 return kElfMachX64;
406 #elif defined(TARGET_ARCH_ARM)
407 return kElfMachARM;
408 #elif defined(TARGET_ARCH_MIPS)
409 return kElfMachMIPS;
410 #else
411 #error Unknown architecture.
412 #endif
413 }
414
415 pid_t gettid() {
416 // libc doesn't wrap the Linux-specific gettid system call.
417 // Note that this thread id is not the same as the posix thread id.
418 return syscall(SYS_gettid);
419 }
420
421 uint64_t GetKernelTimeNanos() {
422 if (clock_id_ != kInvalidClockId) {
423 struct timespec ts;
424 int r = clock_gettime(clock_id_, &ts);
425 ASSERT(r == 0);
426 uint64_t nanos = static_cast<uint64_t>(ts.tv_sec) *
427 static_cast<uint64_t>(kNanosecondsPerSecond);
428 nanos += static_cast<uint64_t>(ts.tv_nsec);
429 return nanos;
430 } else {
431 return OS::GetCurrentTimeMicros() * kNanosecondsPerMicrosecond;
432 }
433 }
434
435 void WriteHeader() {
436 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
437 ASSERT(file_write != NULL);
438 ASSERT(out_file_ != NULL);
439 jitheader header;
440 header.magic = kJitHeaderMagic;
441 header.version = kJitHeaderVersion;
442 header.total_size = sizeof(jitheader);
443 header.pad1 = 0xdeadbeef;
444 header.elf_mach = GetElfMach();
445 header.pid = getpid();
446 header.timestamp = GetKernelTimeNanos();
447 {
448 MutexLocker ml(CodeObservers::mutex());
449 (*file_write)(&header, sizeof(header), out_file_);
450 }
451 }
452
453 void WriteCodeLoad(const char* name, uword base, uword prologue_offset,
454 uword code_size, bool optimized) {
455 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
456 ASSERT(file_write != NULL);
457 ASSERT(out_file_ != NULL);
458
459 const char* code_name = GenerateCodeName(name, optimized);
460 const intptr_t code_name_size = strlen(code_name) + 1;
461 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(base);
462
463 jr_code_load code_load;
464 code_load.id = JIT_CODE_LOAD;
465 code_load.total_size = sizeof(code_load) + code_name_size + code_size;
466 code_load.timestamp = GetKernelTimeNanos();
467 code_load.pid = getpid();
468 code_load.tid = gettid();
469 code_load.vma = 0x0; // Our addresses are absolute.
470 code_load.code_addr = base;
471 code_load.code_size = code_size;
472 code_load.align = OS::PreferredCodeAlignment();
473
474 {
475 MutexLocker ml(CodeObservers::mutex());
476 // Set this field under the index.
477 code_load.code_index = code_sequence_++;
478 // Write structures.
479 (*file_write)(&code_load, sizeof(code_load), out_file_);
480 (*file_write)(code_name, code_name_size, out_file_);
481 (*file_write)(code_pointer, code_size, out_file_);
482 }
483 }
484
485 void* out_file_;
486 int clock_fd_;
487 int clock_id_;
488 uint64_t code_sequence_;
489 DISALLOW_COPY_AND_ASSIGN(JitdumpCodeObserver);
490 };
491
492
272 const char* OS::Name() { 493 const char* OS::Name() {
273 return "linux"; 494 return "linux";
274 } 495 }
275 496
276 497
277 intptr_t OS::ProcessId() { 498 intptr_t OS::ProcessId() {
278 return static_cast<intptr_t>(getpid()); 499 return static_cast<intptr_t>(getpid());
279 } 500 }
280 501
281 502
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 } 726 }
506 if (FLAG_generate_perf_events_symbols) { 727 if (FLAG_generate_perf_events_symbols) {
507 CodeObservers::Register(new PerfCodeObserver); 728 CodeObservers::Register(new PerfCodeObserver);
508 } 729 }
509 if (FLAG_generate_gdb_symbols) { 730 if (FLAG_generate_gdb_symbols) {
510 CodeObservers::Register(new GdbCodeObserver); 731 CodeObservers::Register(new GdbCodeObserver);
511 } 732 }
512 if (FLAG_generate_pprof_symbols != NULL) { 733 if (FLAG_generate_pprof_symbols != NULL) {
513 CodeObservers::Register(new PprofCodeObserver); 734 CodeObservers::Register(new PprofCodeObserver);
514 } 735 }
736 if (FLAG_generate_perf_jitdump) {
737 CodeObservers::Register(new JitdumpCodeObserver);
738 }
515 #if defined(DART_VTUNE_SUPPORT) 739 #if defined(DART_VTUNE_SUPPORT)
516 CodeObservers::Register(new VTuneCodeObserver); 740 CodeObservers::Register(new VTuneCodeObserver);
517 #endif 741 #endif
518 } 742 }
519 743
520 744
521 void OS::PrintErr(const char* format, ...) { 745 void OS::PrintErr(const char* format, ...) {
522 va_list args; 746 va_list args;
523 va_start(args, format); 747 va_start(args, format);
524 VFPrint(stderr, format, args); 748 VFPrint(stderr, format, args);
(...skipping 20 matching lines...) Expand all
545 } 769 }
546 770
547 771
548 void OS::Exit(int code) { 772 void OS::Exit(int code) {
549 exit(code); 773 exit(code);
550 } 774 }
551 775
552 } // namespace dart 776 } // namespace dart
553 777
554 #endif // defined(TARGET_OS_LINUX) 778 #endif // defined(TARGET_OS_LINUX)
OLDNEW
« no previous file with comments | « runtime/vm/code_observers.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698