32 #include <semaphore.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
37 #include <sys/ucontext.h>
40 #include <sys/types.h>
43 #include <sys/fcntl.h>
67 static const pthread_t kNoThread = (pthread_t) 0;
72 if (-1.0 < x && x < 0.0) {
80 static Mutex* limit_mutex =
NULL;
89 __asm__ __volatile__(
"" : : :
"memory");
106 if (
isnan(time))
return "";
107 time_t tv =
static_cast<time_t
>(floor(time/msPerSecond));
108 struct tm* t = localtime(&tv);
109 if (
NULL == t)
return "";
115 time_t tv = time(
NULL);
116 struct tm* t = localtime(&tv);
118 return static_cast<double>(t->tm_gmtoff * msPerSecond -
119 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
128 static void* lowest_ever_allocated =
reinterpret_cast<void*
>(-1);
129 static void* highest_ever_allocated =
reinterpret_cast<void*
>(0);
132 static void UpdateAllocatedSpaceLimits(
void* address,
int size) {
134 ScopedLock lock(limit_mutex);
136 lowest_ever_allocated =
Min(lowest_ever_allocated, address);
137 highest_ever_allocated =
138 Max(highest_ever_allocated,
139 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
144 return address < lowest_ever_allocated || address >= highest_ever_allocated;
149 return getpagesize();
156 const size_t msize =
RoundUp(requested, getpagesize());
157 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
158 void* mbase = mmap(
NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
160 if (mbase == MAP_FAILED) {
161 LOG(
ISOLATE, StringEvent(
"OS::Allocate",
"mmap failed"));
165 UpdateAllocatedSpaceLimits(mbase, msize);
170 void OS::Free(
void* buf,
const size_t length) {
172 int result = munmap(buf, length);
179 unsigned int ms =
static_cast<unsigned int>(milliseconds);
191 #if (defined(__arm__) || defined(__thumb__))
192 # if defined(CAN_USE_ARMV5_INSTRUCTIONS)
201 class PosixMemoryMappedFile :
public OS::MemoryMappedFile {
204 : file_(file), memory_(memory), size_(size) { }
206 virtual void*
memory() {
return memory_; }
207 virtual int size() {
return size_; }
216 FILE* file = fopen(name,
"r+");
219 fseek(file, 0, SEEK_END);
220 int size = ftell(file);
223 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
224 return new PosixMemoryMappedFile(file, memory, size);
230 FILE* file = fopen(name,
"w+");
232 int result = fwrite(initial, size, 1, file);
238 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
239 return new PosixMemoryMappedFile(file, memory, size);
244 if (memory_) munmap(memory_, size_);
249 static unsigned StringToLong(
char* buffer) {
250 return static_cast<unsigned>(strtol(buffer,
NULL, 16));
255 static const int MAP_LENGTH = 1024;
256 int fd = open(
"/proc/self/maps", O_RDONLY);
259 char addr_buffer[11];
260 addr_buffer[0] =
'0';
261 addr_buffer[1] =
'x';
263 int result = read(fd, addr_buffer + 2, 8);
264 if (result < 8)
break;
265 unsigned start = StringToLong(addr_buffer);
266 result = read(fd, addr_buffer + 2, 1);
267 if (result < 1)
break;
268 if (addr_buffer[2] !=
'-')
break;
269 result = read(fd, addr_buffer + 2, 8);
270 if (result < 8)
break;
271 unsigned end = StringToLong(addr_buffer);
272 char buffer[MAP_LENGTH];
276 if (bytes_read >= MAP_LENGTH - 1)
278 result = read(fd, buffer + bytes_read, 1);
279 if (result < 1)
break;
280 }
while (buffer[bytes_read] !=
'\n');
281 buffer[bytes_read] = 0;
283 if (buffer[3] !=
'x')
continue;
284 char* start_of_path = index(buffer,
'/');
286 if (start_of_path ==
NULL)
continue;
287 buffer[bytes_read] = 0;
288 LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
299 int frames_size = frames.length();
300 ScopedVector<void*> addresses(frames_size);
302 int frames_count =
backtrace(addresses.start(), frames_size);
305 if (symbols ==
NULL) {
309 for (
int i = 0; i < frames_count; i++) {
310 frames[i].address = addresses[i];
327 static const int kMmapFd = -1;
328 static const int kMmapFdOffset = 0;
339 : address_(
NULL), size_(0) {
341 size_t request_size =
RoundUp(size + alignment,
346 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
349 if (reservation == MAP_FAILED)
return;
356 if (aligned_base != base) {
357 size_t prefix_size =
static_cast<size_t>(aligned_base - base);
359 request_size -= prefix_size;
365 if (aligned_size != request_size) {
366 size_t suffix_size = request_size - aligned_size;
367 OS::Free(aligned_base + aligned_size, suffix_size);
368 request_size -= suffix_size;
371 ASSERT(aligned_size == request_size);
373 address_ =
static_cast<void*
>(aligned_base);
374 size_ = aligned_size;
388 return address_ !=
NULL;
418 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
422 if (result == MAP_FAILED)
return NULL;
429 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
430 if (MAP_FAILED == mmap(base,
433 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
439 UpdateAllocatedSpaceLimits(base, size);
448 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
450 kMmapFdOffset) != MAP_FAILED;
455 return munmap(base, size) == 0;
466 : data_(new PlatformData),
467 stack_size_(options.stack_size()) {
468 set_name(options.name());
477 static void* ThreadEntry(
void* arg) {
478 Thread* thread =
reinterpret_cast<Thread*
>(arg);
482 thread->data()->thread_ = pthread_self();
483 ASSERT(thread->data()->thread_ != kNoThread);
489 void Thread::set_name(
const char* name) {
490 strncpy(name_, name,
sizeof(name_));
491 name_[
sizeof(name_) - 1] =
'\0';
496 pthread_attr_t* attr_ptr =
NULL;
498 if (stack_size_ > 0) {
499 pthread_attr_init(&attr);
500 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
503 pthread_create(&data_->
thread_, attr_ptr, ThreadEntry,
this);
515 int result = pthread_key_create(&key,
NULL);
523 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
524 int result = pthread_key_delete(pthread_key);
531 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
532 return pthread_getspecific(pthread_key);
537 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
538 pthread_setspecific(pthread_key, value);
550 pthread_mutexattr_t attrs;
551 int result = pthread_mutexattr_init(&attrs);
553 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
555 result = pthread_mutex_init(&mutex_, &attrs);
563 int result = pthread_mutex_lock(&mutex_);
568 int result = pthread_mutex_unlock(&mutex_);
573 int result = pthread_mutex_trylock(&mutex_);
575 if (result == EBUSY) {
583 pthread_mutex_t mutex_;
588 return new FreeBSDMutex();
598 virtual bool Wait(
int timeout);
599 virtual void Signal() { sem_post(&sem_); }
607 int result = sem_wait(&sem_);
608 if (result == 0)
return;
609 CHECK(result == -1 && errno == EINTR);
615 const long kOneSecondMicros = 1000000;
618 struct timeval delta;
619 delta.tv_usec = timeout % kOneSecondMicros;
620 delta.tv_sec = timeout / kOneSecondMicros;
622 struct timeval current_time;
624 if (gettimeofday(¤t_time,
NULL) == -1) {
629 struct timeval end_time;
630 timeradd(¤t_time, &delta, &end_time);
635 int result = sem_timedwait(&sem_, &ts);
636 if (result == 0)
return true;
637 if (result == -1 && errno == ETIMEDOUT)
return false;
638 CHECK(result == -1 && errno == EINTR);
648 static pthread_t GetThreadID() {
649 pthread_t thread_id = pthread_self();
654 class Sampler::PlatformData :
public Malloced {
658 pthread_t
vm_tid()
const {
return vm_tid_; }
665 static void ProfilerSignalHandler(
int signal, siginfo_t* info,
void* context) {
667 if (signal != SIGPROF)
return;
668 Isolate* isolate = Isolate::UncheckedCurrent();
679 if (sampler ==
NULL || !sampler->IsActive())
return;
681 TickSample sample_obj;
683 if (sample ==
NULL) sample = &sample_obj;
686 ucontext_t* ucontext =
reinterpret_cast<ucontext_t*
>(context);
687 mcontext_t& mcontext = ucontext->uc_mcontext;
689 #if V8_HOST_ARCH_IA32
690 sample->pc =
reinterpret_cast<Address>(mcontext.mc_eip);
691 sample->sp =
reinterpret_cast<Address>(mcontext.mc_esp);
692 sample->fp =
reinterpret_cast<Address>(mcontext.mc_ebp);
693 #elif V8_HOST_ARCH_X64
694 sample->pc =
reinterpret_cast<Address>(mcontext.mc_rip);
695 sample->sp =
reinterpret_cast<Address>(mcontext.mc_rsp);
696 sample->fp =
reinterpret_cast<Address>(mcontext.mc_rbp);
697 #elif V8_HOST_ARCH_ARM
698 sample->pc =
reinterpret_cast<Address>(mcontext.mc_r15);
699 sample->sp =
reinterpret_cast<Address>(mcontext.mc_r13);
700 sample->fp =
reinterpret_cast<Address>(mcontext.mc_r11);
702 sampler->SampleStack(sample);
703 sampler->Tick(sample);
729 sa.sa_sigaction = ProfilerSignalHandler;
730 sigemptyset(&sa.sa_mask);
731 sa.sa_flags = SA_RESTART | SA_SIGINFO;
764 bool cpu_profiling_enabled =
769 if (!cpu_profiling_enabled) {
772 if (cpu_profiling_enabled && runtime_profiler_enabled) {
782 if (cpu_profiling_enabled) {
788 if (runtime_profiler_enabled) {
812 pthread_kill(tid, SIGPROF);
818 useconds_t interval =
interval_ * 1000 - 100;
820 int result = usleep(interval);
822 if (result != 0 && errno != EINTR) {
824 "SignalSender usleep error; interval = %u, errno = %d\n",
827 ASSERT(result == 0 || errno == EINTR);
858 uint64_t
seed =
static_cast<uint64_t
>(TimeCurrentMillis());
859 srandom(static_cast<unsigned int>(
seed));
860 limit_mutex = CreateMutex();
877 data_ =
new PlatformData;
static void * GetThreadLocal(LocalStorageKey key)
static void Free(void *address, const size_t size)
Thread(const Options &options)
PlatformData * platform_data()
StateTag current_vm_state()
#define LOG(isolate, Call)
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)
static struct sigaction old_signal_handler_
#define ASSERT(condition)
ThreadManager * thread_manager()
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)
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()
FreeBSDSemaphore(int count)
activate correct semantics for inheriting readonliness false
static void DeleteThreadLocalKey(LocalStorageKey key)
static void Sleep(const int milliseconds)
bool IsLockedByCurrentThread()
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)
virtual ~FreeBSDSemaphore()
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 const int kSignalSenderStackSize
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()
RuntimeProfilerRateLimiter rate_limiter_
static bool IterateActiveSamplers(VisitSampler func, void *param)
static void RemoveActiveSampler(Sampler *sampler)
static double LocalTimeOffset()
static bool signal_handler_installed_
static intptr_t CommitPageSize()
bool Uncommit(void *address, size_t size)
static void DoCpuProfile(Sampler *sampler, void *raw_sender)