32 #include <semaphore.h>
34 #include <sys/prctl.h>
36 #include <sys/resource.h>
37 #include <sys/syscall.h>
38 #include <sys/types.h>
44 #include <sys/types.h>
49 #if defined(__GLIBC__) && !defined(__UCLIBC__)
51 #endif // defined(__GLIBC__) && !defined(__UCLIBC__)
58 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
59 defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
60 #include <asm/sigcontext.h>
78 static const pthread_t kNoThread = (pthread_t) 0;
86 static Mutex* limit_mutex =
NULL;
100 static bool CPUInfoContainsString(
const char * search_string) {
101 const char* file_name =
"/proc/cpuinfo";
107 const char* what = search_string;
109 if (
NULL == (f = fopen(file_name,
"r")))
113 while (EOF != (k = fgetc(f))) {
116 while ((*what !=
'\0') && (*what == fgetc(f))) {
123 what = search_string;
135 const char* search_string =
NULL;
143 search_string =
"vfp";
146 search_string =
"vfpv3";
149 search_string =
"ARMv7";
152 search_string =
"idiva";
158 if (CPUInfoContainsString(search_string)) {
162 if (feature ==
VFP3) {
168 if (CPUInfoContainsString(
"vfp") && CPUInfoContainsString(
"neon")) {
178 static bool use_cached_value =
false;
180 if (use_cached_value) {
183 if (CPUInfoContainsString(
"CPU implementer\t: 0x41")) {
185 }
else if (CPUInfoContainsString(
"CPU implementer\t: 0x51")) {
190 use_cached_value =
true;
204 #define GCC_VERSION (__GNUC__ * 10000 \
205 + __GNUC_MINOR__ * 100 \
206 + __GNUC_PATCHLEVEL__)
207 #if GCC_VERSION >= 40600
208 #if defined(__ARM_PCS_VFP)
214 #elif GCC_VERSION < 40500
218 #if defined(__ARM_PCS_VFP)
220 #elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__)
223 #error "Your version of GCC does not report the FP ABI compiled for." \
224 "Please report it on this issue" \
225 "http://code.google.com/p/v8/issues/detail?id=2140"
232 #endif // def __arm__
237 const char* search_string =
NULL;
238 const char* file_name =
"/proc/cpuinfo";
252 search_string =
"FPU";
259 const char* what = search_string;
261 if (
NULL == (f = fopen(file_name,
"r")))
265 while (EOF != (k = fgetc(f))) {
268 while ((*what !=
'\0') && (*what == fgetc(f))) {
275 what = search_string;
284 #endif // def __mips__
288 #ifdef V8_TARGET_ARCH_ARM
292 #elif V8_TARGET_ARCH_MIPS
302 #if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
303 (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
307 __asm__ __volatile__(
"" : : :
"memory");
315 if (
isnan(time))
return "";
316 time_t tv =
static_cast<time_t
>(floor(time/msPerSecond));
317 struct tm* t = localtime(&tv);
318 if (
NULL == t)
return "";
324 time_t tv = time(
NULL);
325 struct tm* t = localtime(&tv);
327 return static_cast<double>(t->tm_gmtoff * msPerSecond -
328 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
337 static void* lowest_ever_allocated =
reinterpret_cast<void*
>(-1);
338 static void* highest_ever_allocated =
reinterpret_cast<void*
>(0);
341 static void UpdateAllocatedSpaceLimits(
void* address,
int size) {
343 ScopedLock lock(limit_mutex);
345 lowest_ever_allocated =
Min(lowest_ever_allocated, address);
346 highest_ever_allocated =
347 Max(highest_ever_allocated,
348 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
353 return address < lowest_ever_allocated || address >= highest_ever_allocated;
358 return sysconf(_SC_PAGESIZE);
364 bool is_executable) {
366 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
368 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
369 if (mbase == MAP_FAILED) {
370 LOG(i::Isolate::Current(),
371 StringEvent(
"OS::Allocate",
"mmap failed"));
375 UpdateAllocatedSpaceLimits(mbase, msize);
380 void OS::Free(
void* address,
const size_t size) {
382 int result = munmap(address, size);
389 unsigned int ms =
static_cast<unsigned int>(milliseconds);
396 if (FLAG_break_on_abort) {
406 #if (defined(__arm__) || defined(__thumb__))
407 # if defined(CAN_USE_ARMV5_INSTRUCTIONS)
410 #elif defined(__mips__)
418 class PosixMemoryMappedFile :
public OS::MemoryMappedFile {
421 : file_(file), memory_(memory), size_(size) { }
423 virtual void*
memory() {
return memory_; }
424 virtual int size() {
return size_; }
433 FILE* file = fopen(name,
"r+");
436 fseek(file, 0, SEEK_END);
437 int size = ftell(file);
442 PROT_READ | PROT_WRITE,
446 return new PosixMemoryMappedFile(file, memory, size);
452 FILE* file = fopen(name,
"w+");
454 int result = fwrite(initial, size, 1, file);
462 PROT_READ | PROT_WRITE,
466 return new PosixMemoryMappedFile(file, memory, size);
471 if (memory_)
OS::Free(memory_, size_);
480 FILE*
fp = fopen(
"/proc/self/maps",
"r");
481 if (fp ==
NULL)
return;
484 const int kLibNameLen = FILENAME_MAX + 1;
485 char* lib_name =
reinterpret_cast<char*
>(malloc(kLibNameLen));
490 uintptr_t start, end;
491 char attr_r, attr_w, attr_x, attr_p;
494 if (fscanf(fp,
" %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4)
break;
497 if (attr_r ==
'r' && attr_w !=
'w' && attr_x ==
'x') {
502 }
while ((c != EOF) && (c !=
'\n') && (c !=
'/'));
510 if (fgets(lib_name, kLibNameLen, fp) ==
NULL)
break;
515 lib_name[strlen(lib_name) - 1] =
'\0';
518 snprintf(lib_name, kLibNameLen,
519 "%08" V8PRIxPTR
"-%08" V8PRIxPTR, start, end);
521 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
527 }
while ((c != EOF) && (c !=
'\n'));
545 int size = sysconf(_SC_PAGESIZE);
546 FILE* f = fopen(FLAG_gc_fake_mmap,
"w+");
549 PROT_READ | PROT_EXEC,
553 ASSERT(addr != MAP_FAILED);
561 #if defined(__GLIBC__) && !defined(__UCLIBC__)
562 int frames_size = frames.length();
563 ScopedVector<void*> addresses(frames_size);
565 int frames_count =
backtrace(addresses.start(), frames_size);
568 if (symbols ==
NULL) {
572 for (
int i = 0; i < frames_count; i++) {
573 frames[i].address = addresses[i];
586 #else // defined(__GLIBC__) && !defined(__UCLIBC__)
588 #endif // defined(__GLIBC__) && !defined(__UCLIBC__)
593 static const int kMmapFd = -1;
594 static const int kMmapFdOffset = 0;
605 : address_(
NULL), size_(0) {
607 size_t request_size =
RoundUp(size + alignment,
612 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
615 if (reservation == MAP_FAILED)
return;
622 if (aligned_base != base) {
623 size_t prefix_size =
static_cast<size_t>(aligned_base - base);
625 request_size -= prefix_size;
631 if (aligned_size != request_size) {
632 size_t suffix_size = request_size - aligned_size;
633 OS::Free(aligned_base + aligned_size, suffix_size);
634 request_size -= suffix_size;
637 ASSERT(aligned_size == request_size);
639 address_ =
static_cast<void*
>(aligned_base);
640 size_ = aligned_size;
654 return address_ !=
NULL;
684 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
688 if (result == MAP_FAILED)
return NULL;
695 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
696 if (MAP_FAILED == mmap(base,
699 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
705 UpdateAllocatedSpaceLimits(base, size);
714 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
716 kMmapFdOffset) != MAP_FAILED;
721 return munmap(base, size) == 0;
725 class Thread::PlatformData :
public Malloced {
733 : data_(new PlatformData()),
734 stack_size_(options.stack_size()) {
735 set_name(options.name());
744 static void* ThreadEntry(
void* arg) {
751 reinterpret_cast<unsigned long>(thread->name()),
754 thread->data()->thread_ = pthread_self();
755 ASSERT(thread->data()->thread_ != kNoThread);
761 void Thread::set_name(
const char* name) {
762 strncpy(name_, name,
sizeof(name_));
763 name_[
sizeof(name_) - 1] =
'\0';
768 pthread_attr_t* attr_ptr =
NULL;
770 if (stack_size_ > 0) {
771 pthread_attr_init(&attr);
772 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
775 int result = pthread_create(&data_->
thread_, attr_ptr, ThreadEntry,
this);
788 int result = pthread_key_create(&key,
NULL);
796 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
797 int result = pthread_key_delete(pthread_key);
804 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
805 return pthread_getspecific(pthread_key);
810 pthread_key_t pthread_key =
static_cast<pthread_key_t
>(key);
811 pthread_setspecific(pthread_key, value);
823 pthread_mutexattr_t attrs;
824 int result = pthread_mutexattr_init(&attrs);
826 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
828 result = pthread_mutex_init(&mutex_, &attrs);
836 int result = pthread_mutex_lock(&mutex_);
841 int result = pthread_mutex_unlock(&mutex_);
846 int result = pthread_mutex_trylock(&mutex_);
848 if (result == EBUSY) {
856 pthread_mutex_t mutex_;
861 return new LinuxMutex();
871 virtual bool Wait(
int timeout);
872 virtual void Signal() { sem_post(&sem_); }
880 int result = sem_wait(&sem_);
881 if (result == 0)
return;
882 CHECK(result == -1 && errno == EINTR);
887 #ifndef TIMEVAL_TO_TIMESPEC
888 #define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
889 (ts)->tv_sec = (tv)->tv_sec; \
890 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
896 const long kOneSecondMicros = 1000000;
899 struct timeval delta;
900 delta.tv_usec = timeout % kOneSecondMicros;
901 delta.tv_sec = timeout / kOneSecondMicros;
903 struct timeval current_time;
905 if (gettimeofday(¤t_time,
NULL) == -1) {
910 struct timeval end_time;
911 timeradd(¤t_time, &delta, &end_time);
917 int result = sem_timedwait(&sem_, &ts);
918 if (result == 0)
return true;
924 if (result == -1 && errno == ETIMEDOUT)
return false;
925 CHECK(result == -1 && errno == EINTR);
935 #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
946 typedef struct sigcontext mcontext_t;
948 typedef struct ucontext {
950 struct ucontext* uc_link;
952 mcontext_t uc_mcontext;
956 #elif defined(__mips__)
979 typedef struct ucontext {
981 struct ucontext* uc_link;
983 mcontext_t uc_mcontext;
987 #elif defined(__i386__)
996 typedef uint32_t kernel_sigset_t[2];
997 typedef struct ucontext {
999 struct ucontext* uc_link;
1001 mcontext_t uc_mcontext;
1004 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
1007 #endif // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
1009 static int GetThreadID() {
1010 #if defined(__ANDROID__)
1015 return syscall(SYS_gettid);
1020 static void ProfilerSignalHandler(
int signal, siginfo_t* info,
void* context) {
1022 if (signal != SIGPROF)
return;
1023 Isolate* isolate = Isolate::UncheckedCurrent();
1024 if (isolate ==
NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
1029 !isolate->thread_manager()->IsLockedByCurrentThread()) {
1033 Sampler* sampler = isolate->logger()->sampler();
1034 if (sampler ==
NULL || !sampler->IsActive())
return;
1036 TickSample sample_obj;
1038 if (sample ==
NULL) sample = &sample_obj;
1041 ucontext_t* ucontext =
reinterpret_cast<ucontext_t*
>(context);
1042 mcontext_t& mcontext = ucontext->uc_mcontext;
1043 sample->state = isolate->current_vm_state();
1044 #if V8_HOST_ARCH_IA32
1045 sample->pc =
reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
1046 sample->sp =
reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
1047 sample->fp =
reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
1048 #elif V8_HOST_ARCH_X64
1049 sample->pc =
reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
1050 sample->sp =
reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
1051 sample->fp =
reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
1052 #elif V8_HOST_ARCH_ARM
1053 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
1054 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1057 sample->pc =
reinterpret_cast<Address>(mcontext.gregs[R15]);
1058 sample->sp =
reinterpret_cast<Address>(mcontext.gregs[R13]);
1059 sample->fp =
reinterpret_cast<Address>(mcontext.gregs[R11]);
1061 sample->pc =
reinterpret_cast<Address>(mcontext.arm_pc);
1062 sample->sp =
reinterpret_cast<Address>(mcontext.arm_sp);
1063 sample->fp =
reinterpret_cast<Address>(mcontext.arm_fp);
1064 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
1066 #elif V8_HOST_ARCH_MIPS
1067 sample->pc =
reinterpret_cast<Address>(mcontext.pc);
1068 sample->sp =
reinterpret_cast<Address>(mcontext.gregs[29]);
1069 sample->fp =
reinterpret_cast<Address>(mcontext.gregs[30]);
1070 #endif // V8_HOST_ARCH_*
1071 sampler->SampleStack(sample);
1072 sampler->Tick(sample);
1076 class Sampler::PlatformData :
public Malloced {
1094 static const int kSignalSenderStackSize = 64 *
KB;
1099 interval_(interval) {}
1105 struct sigaction sa;
1106 sa.sa_sigaction = ProfilerSignalHandler;
1107 sigemptyset(&sa.sa_mask);
1108 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1109 signal_handler_installed_ =
1110 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
1114 if (signal_handler_installed_) {
1115 sigaction(SIGPROF, &old_signal_handler_, 0);
1116 signal_handler_installed_ =
false;
1123 if (instance_ ==
NULL) {
1140 RestoreSignalHandler();
1149 bool cpu_profiling_enabled =
1152 if (cpu_profiling_enabled && !signal_handler_installed_) {
1153 InstallSignalHandler();
1154 }
else if (!cpu_profiling_enabled && signal_handler_installed_) {
1155 RestoreSignalHandler();
1159 if (!cpu_profiling_enabled) {
1160 if (rate_limiter_.SuspendIfNecessary())
continue;
1162 if (cpu_profiling_enabled && runtime_profiler_enabled) {
1166 Sleep(HALF_INTERVAL);
1170 Sleep(HALF_INTERVAL);
1172 if (cpu_profiling_enabled) {
1178 if (runtime_profiler_enabled) {
1184 Sleep(FULL_INTERVAL);
1201 if (!signal_handler_installed_)
return;
1203 #if defined(ANDROID)
1204 syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
1206 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
1213 useconds_t interval = interval_ * 1000 - 100;
1214 if (full_or_half == HALF_INTERVAL) interval /= 2;
1215 #if defined(ANDROID)
1218 int result = usleep(interval);
1220 if (result != 0 && errno != EINTR) {
1222 "SignalSender usleep error; interval = %u, errno = %d\n",
1225 ASSERT(result == 0 || errno == EINTR);
1233 const int interval_;
1234 RuntimeProfilerRateLimiter rate_limiter_;
1237 static Mutex* mutex_;
1239 static bool signal_handler_installed_;
1240 static struct sigaction old_signal_handler_;
1255 uint64_t
seed = Ticks() ^ (getpid() << 16);
1256 srandom(static_cast<unsigned int>(
seed));
1257 limit_mutex = CreateMutex();
1264 #if !USE_EABI_HARDFLOAT
1265 PrintF(
"ERROR: Binary compiled with -mfloat-abi=hard but without "
1266 "-DUSE_EABI_HARDFLOAT\n");
1270 #if USE_EABI_HARDFLOAT
1271 PrintF(
"ERROR: Binary not compiled with -mfloat-abi=hard but with "
1272 "-DUSE_EABI_HARDFLOAT\n");
1288 : isolate_(isolate),
1289 interval_(interval),
1293 data_ =
new PlatformData;
static void * GetThreadLocal(LocalStorageKey key)
#define CHECK_EQ(expected, value)
static void Free(void *address, const size_t size)
void PrintF(const char *format,...)
LinuxSemaphore(int count)
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)
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)
static bool ArmCpuHasFeature(CpuFeature feature)
T RoundUp(T x, intptr_t m)
#define ASSERT_LE(v1, v2)
static Mutex * CreateMutex()
static CpuImplementer GetCpuImplementer()
static bool MipsCpuHasFeature(CpuFeature feature)
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)
virtual ~LinuxSemaphore()
static bool CommitRegion(void *base, size_t size, bool is_executable)
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_
void SendProfilingSignal(int tid)
static bool ArmUsingHardFloat()
static intptr_t CommitPageSize()
bool Uncommit(void *address, size_t size)
static void DoCpuProfile(Sampler *sampler, void *raw_sender)