32 #include <semaphore.h>
35 #include <sys/resource.h>
36 #include <sys/syscall.h>
37 #include <sys/types.h>
40 #include <sys/types.h>
65 static const pthread_t kNoThread = (pthread_t) 0;
73 static Mutex* limit_mutex =
NULL;
76 static void* GetRandomMmapAddr() {
77 Isolate* isolate = Isolate::UncheckedCurrent();
81 if (isolate !=
NULL) {
82 #ifdef V8_TARGET_ARCH_X64
85 uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
89 raw_addr &= V8_UINT64_C(0x3ffffffff000);
94 raw_addr &= 0x3ffff000;
95 raw_addr += 0x20000000;
97 return reinterpret_cast<void*
>(raw_addr);
121 __asm__ __volatile__(
"" : : :
"memory");
128 if (
isnan(time))
return "";
129 time_t tv =
static_cast<time_t
>(floor(time/msPerSecond));
130 struct tm* t = localtime(&tv);
131 if (
NULL == t)
return "";
137 time_t tv = time(
NULL);
138 struct tm* t = localtime(&tv);
140 return static_cast<double>(t->tm_gmtoff * msPerSecond -
141 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
150 static void* lowest_ever_allocated =
reinterpret_cast<void*
>(-1);
151 static void* highest_ever_allocated =
reinterpret_cast<void*
>(0);
154 static void UpdateAllocatedSpaceLimits(
void* address,
int size) {
156 ScopedLock lock(limit_mutex);
158 lowest_ever_allocated =
Min(lowest_ever_allocated, address);
159 highest_ever_allocated =
160 Max(highest_ever_allocated,
161 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
166 return address < lowest_ever_allocated || address >= highest_ever_allocated;
171 return sysconf(_SC_PAGESIZE);
177 bool is_executable) {
179 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
181 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
182 if (mbase == MAP_FAILED) {
183 LOG(i::Isolate::Current(),
184 StringEvent(
"OS::Allocate",
"mmap failed"));
188 UpdateAllocatedSpaceLimits(mbase, msize);
193 void OS::Free(
void* address,
const size_t size) {
195 int result = munmap(address, size);
202 unsigned int ms =
static_cast<unsigned int>(milliseconds);
218 class PosixMemoryMappedFile :
public OS::MemoryMappedFile {
221 : file_(file), memory_(memory), size_(size) { }
223 virtual void*
memory() {
return memory_; }
224 virtual int size() {
return size_; }
233 FILE* file = fopen(name,
"r+");
236 fseek(file, 0, SEEK_END);
237 int size = ftell(file);
240 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
241 return new PosixMemoryMappedFile(file, memory, size);
247 FILE* file = fopen(name,
"w+");
249 int result = fwrite(initial, size, 1, file);
255 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
256 return new PosixMemoryMappedFile(file, memory, size);
261 if (memory_)
OS::Free(memory_, size_);
270 FILE*
fp = fopen(
"/proc/self/maps",
"r");
271 if (fp ==
NULL)
return;
274 const int kLibNameLen = FILENAME_MAX + 1;
275 char* lib_name =
reinterpret_cast<char*
>(malloc(kLibNameLen));
280 uintptr_t start, end;
281 char attr_r, attr_w, attr_x, attr_p;
284 if (fscanf(fp,
" %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4)
break;
287 if (attr_r ==
'r' && attr_w !=
'w' && attr_x ==
'x') {
292 }
while ((c != EOF) && (c !=
'\n') && (c !=
'/'));
300 if (fgets(lib_name, kLibNameLen, fp) ==
NULL)
break;
305 lib_name[strlen(lib_name) - 1] =
'\0';
308 snprintf(lib_name, kLibNameLen,
309 "%08" V8PRIxPTR
"-%08" V8PRIxPTR, start, end);
311 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
317 }
while ((c != EOF) && (c !=
'\n'));
335 int size = sysconf(_SC_PAGESIZE);
336 FILE* f = fopen(FLAG_gc_fake_mmap,
"w+");
337 void* addr = mmap(
NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE,
339 ASSERT(addr != MAP_FAILED);
347 int frames_size = frames.length();
348 ScopedVector<void*> addresses(frames_size);
350 int frames_count =
backtrace(addresses.start(), frames_size);
353 if (symbols ==
NULL) {
357 for (
int i = 0; i < frames_count; i++) {
358 frames[i].address = addresses[i];
375 static const int kMmapFd = -1;
376 static const int kMmapFdOffset = 0;
387 : address_(
NULL), size_(0) {
389 size_t request_size =
RoundUp(size + alignment,
391 void* reservation = mmap(GetRandomMmapAddr(),
394 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
397 if (reservation == MAP_FAILED)
return;
404 if (aligned_base != base) {
405 size_t prefix_size =
static_cast<size_t>(aligned_base - base);
407 request_size -= prefix_size;
413 if (aligned_size != request_size) {
414 size_t suffix_size = request_size - aligned_size;
415 OS::Free(aligned_base + aligned_size, suffix_size);
416 request_size -= suffix_size;
419 ASSERT(aligned_size == request_size);
421 address_ =
static_cast<void*
>(aligned_base);
422 size_ = aligned_size;
436 return address_ !=
NULL;
463 void* result = mmap(GetRandomMmapAddr(),
466 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
470 if (result == MAP_FAILED)
return NULL;
477 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
478 if (MAP_FAILED == mmap(base,
481 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
487 UpdateAllocatedSpaceLimits(base, size);
496 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
498 kMmapFdOffset) != MAP_FAILED;
503 return munmap(base, size) == 0;
507 class Thread::PlatformData :
public Malloced {
515 : data_(new PlatformData()),
516 stack_size_(options.stack_size()) {
517 set_name(options.name());
526 static void* ThreadEntry(
void* arg) {
533 reinterpret_cast<unsigned long>(thread->name()),
536 thread->data()->thread_ = pthread_self();
537 ASSERT(thread->data()->thread_ != kNoThread);
543 void Thread::set_name(
const char* name) {
544 strncpy(name_, name,
sizeof(name_));
545 name_[
sizeof(name_) - 1] =
'\0';
550 pthread_attr_t* attr_ptr =
NULL;
552 if (stack_size_ > 0) {
553 pthread_attr_init(&attr);
554 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
557 pthread_create(&data_->
thread_, attr_ptr, ThreadEntry,
this);
569 int result = pthread_key_create(&key,
NULL);
577 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
578 int result = pthread_key_delete(pthread_key);
585 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
586 return pthread_getspecific(pthread_key);
591 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
592 pthread_setspecific(pthread_key, value);
604 pthread_mutexattr_t attrs;
605 int result = pthread_mutexattr_init(&attrs);
607 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
609 result = pthread_mutex_init(&mutex_, &attrs);
617 int result = pthread_mutex_lock(&mutex_);
622 int result = pthread_mutex_unlock(&mutex_);
627 int result = pthread_mutex_trylock(&mutex_);
629 if (result == EBUSY) {
637 pthread_mutex_t mutex_;
642 return new OpenBSDMutex();
652 virtual bool Wait(
int timeout);
653 virtual void Signal() { sem_post(&sem_); }
661 int result = sem_wait(&sem_);
662 if (result == 0)
return;
663 CHECK(result == -1 && errno == EINTR);
668 #ifndef TIMEVAL_TO_TIMESPEC
669 #define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
670 (ts)->tv_sec = (tv)->tv_sec; \
671 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
677 const long kOneSecondMicros = 1000000;
680 struct timeval delta;
681 delta.tv_usec = timeout % kOneSecondMicros;
682 delta.tv_sec = timeout / kOneSecondMicros;
684 struct timeval current_time;
686 if (gettimeofday(¤t_time,
NULL) == -1) {
691 struct timeval end_time;
692 timeradd(¤t_time, &delta, &end_time);
700 int result = sem_trywait(&sem_);
701 if (result == 0)
return true;
702 if (!to)
return false;
703 CHECK(result == -1 && errno == EINTR);
704 usleep(ts.tv_nsec / 1000);
714 static pthread_t GetThreadID() {
715 return pthread_self();
718 static void ProfilerSignalHandler(
int signal, siginfo_t* info,
void* context) {
720 if (signal != SIGPROF)
return;
721 Isolate* isolate = Isolate::UncheckedCurrent();
722 if (isolate ==
NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
727 !isolate->thread_manager()->IsLockedByCurrentThread()) {
731 Sampler* sampler = isolate->logger()->sampler();
732 if (sampler ==
NULL || !sampler->IsActive())
return;
734 TickSample sample_obj;
736 if (sample ==
NULL) sample = &sample_obj;
739 sample->state = isolate->current_vm_state();
740 ucontext_t* ucontext =
reinterpret_cast<ucontext_t*
>(context);
742 mcontext_t& mcontext = ucontext->uc_mcontext;
743 #if V8_HOST_ARCH_IA32
744 sample->pc =
reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
745 sample->sp =
reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
746 sample->fp =
reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
747 #elif V8_HOST_ARCH_X64
748 sample->pc =
reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
749 sample->sp =
reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
750 sample->fp =
reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
751 #endif // V8_HOST_ARCH
753 #if V8_HOST_ARCH_IA32
754 sample->pc =
reinterpret_cast<Address>(ucontext->sc_eip);
755 sample->sp =
reinterpret_cast<Address>(ucontext->sc_esp);
756 sample->fp =
reinterpret_cast<Address>(ucontext->sc_ebp);
757 #elif V8_HOST_ARCH_X64
758 sample->pc =
reinterpret_cast<Address>(ucontext->sc_rip);
759 sample->sp =
reinterpret_cast<Address>(ucontext->sc_rsp);
760 sample->fp =
reinterpret_cast<Address>(ucontext->sc_rbp);
761 #endif // V8_HOST_ARCH
763 sampler->SampleStack(sample);
764 sampler->Tick(sample);
768 class Sampler::PlatformData :
public Malloced {
772 pthread_t
vm_tid()
const {
return vm_tid_; }
786 static const int kSignalSenderStackSize = 64 *
KB;
791 interval_(interval) {}
798 sa.sa_sigaction = ProfilerSignalHandler;
799 sigemptyset(&sa.sa_mask);
800 sa.sa_flags = SA_RESTART | SA_SIGINFO;
801 signal_handler_installed_ =
802 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
806 if (signal_handler_installed_) {
807 sigaction(SIGPROF, &old_signal_handler_, 0);
808 signal_handler_installed_ =
false;
815 if (instance_ ==
NULL) {
832 RestoreSignalHandler();
841 bool cpu_profiling_enabled =
844 if (cpu_profiling_enabled && !signal_handler_installed_) {
845 InstallSignalHandler();
846 }
else if (!cpu_profiling_enabled && signal_handler_installed_) {
847 RestoreSignalHandler();
851 if (!cpu_profiling_enabled) {
852 if (rate_limiter_.SuspendIfNecessary())
continue;
854 if (cpu_profiling_enabled && runtime_profiler_enabled) {
858 Sleep(HALF_INTERVAL);
862 Sleep(HALF_INTERVAL);
864 if (cpu_profiling_enabled) {
870 if (runtime_profiler_enabled) {
876 Sleep(FULL_INTERVAL);
893 if (!signal_handler_installed_)
return;
894 pthread_kill(tid, SIGPROF);
900 useconds_t interval = interval_ * 1000 - 100;
901 if (full_or_half == HALF_INTERVAL) interval /= 2;
902 int result = usleep(interval);
904 if (result != 0 && errno != EINTR) {
906 "SignalSender usleep error; interval = %u, errno = %d\n",
909 ASSERT(result == 0 || errno == EINTR);
917 RuntimeProfilerRateLimiter rate_limiter_;
920 static Mutex* mutex_;
922 static bool signal_handler_installed_;
923 static struct sigaction old_signal_handler_;
932 struct sigaction SignalSender::old_signal_handler_;
938 uint64_t
seed = Ticks() ^ (getpid() << 16);
939 srandom(static_cast<unsigned int>(
seed));
940 limit_mutex = CreateMutex();
957 data_ =
new PlatformData;
static void * GetThreadLocal(LocalStorageKey key)
static void Free(void *address, const size_t size)
Thread(const Options &options)
PlatformData * platform_data()
#define LOG(isolate, Call)
static void InstallSignalHandler()
void SendProfilingSignal(pthread_t tid)
static void SignalCodeMovingGC()
static void * GetRandomMmapAddr()
static void * ReserveRegion(size_t size)
static bool IsOutsideAllocatedSpace(void *pointer)
static const char * LocalTimezone(double time)
Vector< char > MutableCStrVector(char *data)
static const int kStackWalkError
void Sleep(SleepInterval full_or_half)
static const int kStackWalkMaxTextLen
static void DoRuntimeProfile(Sampler *sampler, void *ignored)
PosixMemoryMappedFile(FILE *file, void *memory, int size)
#define ASSERT(condition)
static void RestoreSignalHandler()
static MemoryMappedFile * open(const char *name)
static void RemoveActiveSampler(Sampler *sampler)
virtual void * memory()=0
bool Guard(void *address)
static void StopRuntimeProfilerThreadBeforeShutdown(Thread *thread)
static SignalSender * instance_
static void ReleaseStore(volatile AtomicWord *ptr, AtomicWord value)
RuntimeProfiler * runtime_profiler()
static TickSample * TickSampleEvent(Isolate *isolate)
virtual ~OpenBSDSemaphore()
static LocalStorageKey CreateThreadLocalKey()
SignalSender(int interval)
bool IsAligned(T value, U alignment)
static MemoryMappedFile * create(const char *name, int size, void *initial)
bool Commit(void *address, size_t size, bool is_executable)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
static void Guard(void *address, const size_t size)
T RoundUp(T x, intptr_t m)
#define ASSERT_LE(v1, v2)
static Mutex * CreateMutex()
activate correct semantics for inheriting readonliness false
static void DeleteThreadLocalKey(LocalStorageKey key)
static void Sleep(const int milliseconds)
static int SNPrintF(Vector< char > str, const char *format,...)
static Semaphore * CreateSemaphore(int count)
static bool ReleaseRegion(void *base, size_t size)
static bool CommitRegion(void *base, size_t size, bool is_executable)
static uint32_t RandomPrivate(Isolate *isolate)
static void SetThreadLocal(LocalStorageKey key, void *value)
static void * Allocate(const size_t requested, size_t *allocated, bool is_executable)
static int StackWalk(Vector< StackFrame > frames)
static bool UncommitRegion(void *base, size_t size)
static void LogSharedLibraryAddresses()
virtual ~PosixMemoryMappedFile()
static int ActivationFrameAlignment()
static size_t AllocateAlignment()
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
static void AddActiveSampler(Sampler *sampler)
static void AddActiveSampler(Sampler *sampler)
Sampler(Isolate *isolate, int interval)
static uint64_t CpuFeaturesImpliedByPlatform()
static bool IterateActiveSamplers(VisitSampler func, void *param)
static void RemoveActiveSampler(Sampler *sampler)
static double LocalTimeOffset()
static bool signal_handler_installed_
static intptr_t CommitPageSize()
OpenBSDSemaphore(int count)
bool Uncommit(void *address, size_t size)
static void DoCpuProfile(Sampler *sampler, void *raw_sender)